PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : dynamische mehrdimensionale Arrays wie statische Arrays ansprechen?



HaWe
19.11.2019, 17:55
hallo,
wie kann man dynamische mehrdimensionale Arrays wie statische Arrays ansprechen?
(C-code, aber streng genomen mit cpp kompiliert)

z.B: ich habe einen statischen Array
double arrayst[100][30]
und brauche einen weiteren gleich großen dynamischen
double arraydyn[100][30]

memory allozieren könnte ich per
double *mem = (double*) malloc(100*30*sizeof(double));

aber wie kriege ich das jetzt sauber in einen 2-dim array?
per union?


union a {
double *mem;
double arraydyn[100][30];
}


a.mem=(double*) malloc(100*30*sizeof(double));

for (int i=0; i<100; i++) {
for (int j=0; j<30; j++) {
a.arraydyn[i][j]=arrayst[i][j]*0.123;
}
}

wäre das so korrektes "C"?

Oder geht es weniger umständlich mit C++ und new oder auch ganz anders?

Rumgucker
20.11.2019, 05:03
Moin Helmut,

ich würde mehrdimensionale Arrays möglichst vermeiden, denn irgendwann weiß man nie so genau, was der Compiler da eigentlich indiziert. Lieber klare Verhältnisse schaffen:



#define X 100
#define Y 30
#define IND(x,y) ((x * X) + y)

double arrayst[X * Y] = {47.11, 0.815};
double *arraydyn = (double*)malloc(X*Y*sizeof(double));

for (int i=0; i < X; i++) {
for (int j=0; j < Y; j++) {
arraydyn[IND(i,j)]=arrayst[IND(i,j)]*0.123;
}
}


Wenn das nicht Deinen Geschmack trifft, setz ich mich zum Rumspielen mal an den Compiler.

Viele Grüße

Wolfgang

HaWe
20.11.2019, 08:55
hallo,
danke, aber gerade die dyn. mehrdim. Arrays sind unbedingt wichtig, damit der bestehende, für stat. arrays geschriebene Code 1:1 übenommen werden kann - ansonsten wäre es einfach.
Ich bin allerdings nicht sicher, ob mein Code mit den unions wirklich 100% korrekt ist - oder ob es noch einfachere Wege gibt.

(wichtig: es ist der von Arduino verwendete gpp C++14 Compiler!)

Rumgucker
20.11.2019, 09:07
Hallo Helmut,

so wird Dein Code geschluckt



double arrayst[100][30];

union {
double *mem;
double arraydyn[100][30];
} a;


a.mem=(double*) malloc(100*30*sizeof(double));

for (int i=0; i<100; i++) {
for (int j=0; j<30; j++) {
a.arraydyn[i][j]=arrayst[i][j]*0.123;
}
}


Ich versuch ihn mal zu vereinfachen.

Viele Grüße

Wolfgang

HaWe
20.11.2019, 09:32
ich musste den Code jetzt testweise für den esp8266 "downsizen", offenbar hat der bei weitem zu wenig RAM für heap.
In meiner union-Def. war offenbar auch ein Fehler, ich habe deinen Code mal für mich angepasst:



#define LINE 20
#define ROW 10

void setup() {
Serial.begin(115200);
delay(1000);
Serial.println();
Serial.println("Serial() started");

float arraystat[LINE][ROW ];

union {
float *mem;
float arraydyn[LINE][ROW ]; // 10*20*4=800 bytes
} a;


a.mem = (float*) malloc(LINE * ROW * sizeof(float));

for (int i = 0; i < LINE; i++) {
for (int j = 0; j < ROW ; j++) {
arraystat[j]=i*(j*1000);
}
}

for (int i = 0; i < LINE; i++) {
for (int j = 0; j < ROW ; j++) {
a.arraydyn[i][j] = arraystat[i][j] * 0.01;
}
}

for (int i = 0; i < LINE; i++) {
yield();
for (int j = 0; j < ROW ; j++) {
Serial.println (a.arraydyn[i][j]);
}
}


}

void loop() {


}


- - - Aktualisiert - - -

Sieht gut aus! (edit: zumindest auf den 1. Blick laut Serial.print)
Jetzt wäre nur noch die Frage, ob's auch 2-dim [I]ohne unions geht...

Rumgucker
20.11.2019, 09:42
Hallo Helmut,


Sieht gut aus!

Ich bin noch nicht so ganz überzeugt. Ich denke, dass Dein Union auf einen sinnlosen 3000 double-Speicher zeigt, der dann einfach nie gebraucht wrid, weil er von dem malloc-Zeiger umgangen wird.



Jetzt wäre nur noch die Frage, ob's auch 2-dim ohne unions geht...
Daran grübele ich gerade.

Viele Grüße

Wolfgang

HaWe
20.11.2019, 09:42
Und mir ist auch noch nicht klar, ob die union a wirklich dynamisch im heap angelegt wird (und nicht im stack).
eigentlich müsste es ja im Code per
a->arraydyn[][] gehen, nicht per a.arraydyn[][]
oder nicht?

Rumgucker
20.11.2019, 10:33
Hallo Helmut,

"a->" ist "Pointer auf" und "a." ist "Member von".

Ich bin überzeugt davon, dass die Lösung banal und naheliegend ist. Aber es gibt so Tage, an denen man wie vernagelt ist.

Im Herzen finde ich meine IND-Makro-Lösung immer noch optimal

#define IND(x,y) ((x * X) + y)

und dann

arraydyn[IND(i,j)] = arrayst[IND(i,j)]*0.123;

Und sofort sind alle Probleme wie weggeblasen. Und es tut exakt das, was der Compiler auch tun würde. Denn wir quälen uns ja zur Zeit nur damit ab, dem Compiler genau diese Rechenregel auch für dynamische Arrays beizubrigen. Das ist unser ganzes Problem. Mehr nicht.

Kannst Du Dich nicht vielleicht eventuell möglichweise - und natürlich: unter Protest - doch zu dieser zuerst gezeigten Lösung herablassen? Zumindest so lange, bis uns die Bretter vom Kopf fallen?

Dann wird "IND(x,y)" einfach wieder durch "[x][y]" ersetzt und alles ist wieder gut.

Viele Grüße

Wolfgang

HaWe
20.11.2019, 10:40
es muss wie gesagt unbedingt ein dynamischer 2-dim array sein.

(PS,
und die Lösung soll später auch in analoger Weise für 3- oder 4-dim Arrays funktionieren)

Rumgucker
20.11.2019, 11:13
Hallo Helmut,

wenn Du schreibst:

pointer = malloc(LINE * ROW * sizeof(float));

dann speicherst Du einen Pointer auf ein 1-dimensionales Array. Das will ich nicht ändern.

Wenn Du den Compiler anweist, ein x-dimensionales Array anzulegen, dann speicherst du auch nur den Pointer auf ein 1-dimensionales Array. Die x-Dimensionalität entsteht allein dadurch, dass der Compiler beim Zugriff eine Rechenregel befolgt, die er aus der Definition des Arryas gewonnen hat

Da es uns nicht gelingt, dem Compiler diese n-dimensionale Rechenregel auf für mit malloc erstellte 1-dimensionale Arrays zu übertragen, sollten wir dem Compiler das Rechnen einfach abnehmen.

An Deinen gewünschten Dimensionen und mallocs usw. ändert das doch überhaupt nichts. Wir erklären lediglich den Compiler für doof und sagen ihm per Makro, wie er Arryay-Indizes zu berchnen hat.

Das ermöglicht uns, alle Arrys uniform als double* anzusprechen, obwohl es natürlich unverändert mehrdimensionale Arrays sind. Double ist einfach der kleinste einzeln adressierbare Element aller Arrays.

Von der Laufzeit, Speicherplatzbedarf oder so ändert sich gar nichts. Wir schließen lediglich vom Start weg Missverständnisse zwischen Compiler und uns aus.

BTW: ich seh übrigens noch nen Fehler in meinem IND-Makro:

#define IND(x,y) ((x * X) + y)

Das große X muss natürlich durch ein großes Y ersetzt werden:

#define IND(x,y) ((x * Y) + y)

Himmel.

Viele Grüße

Wolfgang

HaWe
20.11.2019, 11:14
es muss wie gesagt unbedingt ein dynamischer 2-dim array sein.

Rumgucker
20.11.2019, 11:56
Hallo Helmut,

*jammer*

Ok. Ich versuchs nochmal.

Viele Grüße

Wolfgang

- - - Aktualisiert - - -

Hallo Helmut,

ist mein Brett schon vollständig abgefallen oder geht das noch nicht ganz?



float arrayst[100][30];
float** arraydyn = (float **)malloc(sizeof(arrayst));

for (int i=0; i<100; i++) {
for (int j=0; j<30; j++) {
arraydyn[i][j]=arrayst[i][j]*0.123;
}
}


Viele Grüße

Wolfgang

HaWe
20.11.2019, 12:10
das gibt leider Laufzeitfehler:



#define LINE 20
#define ROW 10

void setup() {
Serial.begin(115200);
delay(1000);
Serial.println();
Serial.println("Serial() started");

float arraystat[LINE][ROW ];
float** arraydyn = (float **)malloc(LINE*ROW*sizeof(float));



for (int i = 0; i < LINE; i++) {
for (int j = 0; j < ROW ; j++) {
arraystat[i][j]=i*(j*1000);
}
}

for (int i = 0; i < LINE; i++) {
for (int j = 0; j < ROW ; j++) {
arraydyn[i][j] = arraystat[i][j] * 0.01;
}
}

for (int i = 0; i < LINE; i++) {
yield();
for (int j = 0; j < ROW ; j++) {
Serial.println (arraydyn[i][j]);
}
}


}

void loop() {


}


Serial() started

Exception (29):
epc1=0x4020110a epc2=0x00000000 epc3=0x00000000 excvaddr=0x00b40000 depc=0x00000000

>>>stack>>>

ctx: cont
sp: 3ffffab0 end: 3fffffc0 offset: 01a0
3ffffc50: 00000000 00000000 00000000 00000000
3ffffc60: 00000000 00000000 00000000 00000000
3ffffc70: 00000000 00000000 00000000 447a0000
3ffffc80: 44fa0000 453b8000 457a0000 459c4000
3ffffc90: 45bb8000 45dac000 45fa0000 460ca000
3ffffca0: 00000000 44fa0000 457a0000 45bb8000
3ffffcb0: 45fa0000 461c4000 463b8000 465ac000
3ffffcc0: 467a0000 468ca000 00000000 453b8000
3ffffcd0: 45bb8000 460ca000 463b8000 466a6000
3ffffce0: 468ca000 46a41000 46bb8000 46d2f000
3ffffcf0: 00000000 457a0000 45fa0000 463b8000
3ffffd00: 467a0000 469c4000 46bb8000 46dac000
3ffffd10: 46fa0000 470ca000 00000000 459c4000
3ffffd20: 461c4000 466a6000 469c4000 46c35000
3ffffd30: 46ea6000 4708b800 471c4000 472fc800
3ffffd40: 00000000 45bb8000 463b8000 468ca000
3ffffd50: 46bb8000 46ea6000 470ca000 47241000
3ffffd60: 473b8000 4752f000 00000000 45dac000
3ffffd70: 465ac000 46a41000 46dac000 4708b800
3ffffd80: 47241000 473f6800 475ac000 47761800
3ffffd90: 00000000 45fa0000 467a0000 46bb8000
3ffffda0: 46fa0000 471c4000 473b8000 475ac000
3ffffdb0: 477a0000 478ca000 00000000 460ca000
3ffffdc0: 468ca000 46d2f000 470ca000 472fc800
3ffffdd0: 4752f000 47761800 478ca000 479e3400
3ffffde0: 00000000 461c4000 469c4000 46ea6000
3ffffdf0: 471c4000 47435000 476a6000 4788b800
3ffffe00: 479c4000 47afc800 00000000 462be000
3ffffe10: 46abe000 4700e800 472be000 4756d800
3ffffe20: 4780e800 47966400 47abe000 47c15c00
3ffffe30: 00000000 463b8000 46bb8000 470ca000
3ffffe40: 473b8000 476a6000 478ca000 47a41000
3ffffe50: 47bb8000 47d2f000 00000000 464b2000
3ffffe60: 46cb2000 47185800 474b2000 477de800
3ffffe70: 47985800 47b1bc00 47cb2000 47e48400
3ffffe80: 00000000 465ac000 46dac000 47241000
3ffffe90: 475ac000 4788b800 47a41000 47bf6800
3ffffea0: 47dac000 47f61800 00000000 466a6000
3ffffeb0: 46ea6000 472fc800 476a6000 47927c00
3ffffec0: 47afc800 47cd1400 47ea6000 4803d600
3ffffed0: 00000000 467a0000 46fa0000 473b8000
3ffffee0: 477a0000 479c4000 47bb8000 47dac000
3ffffef0: 47fa0000 480ca000 00000000 4684d000
3fffff00: 4704d000 47473800 4784d000 47a60400
3fffff10: 47c73800 47e86c00 4804d000 48156a00
3fffff20: 00000000 468ca000 470ca000 4752f000
3fffff30: 478ca000 47afc800 47d2f000 47f61800
3fffff40: 480ca000 481e3400 00000000 46947000
3fffff50: 47147000 475ea800 47947000 47b98c00
3fffff60: 47dea800 4801e200 48147000 4826fe00
3fffff70: 3ffeefd4 00b40000 00000028 00000320
3fffff80: 00b40000 feefeffe feefeffe feefeffe
3fffff90: feefeffe feefeffe feefeffe 3ffee29c
3fffffa0: 3fffdad0 00000000 3ffee26c 40201b9c
3fffffb0: feefeffe feefeffe 3ffe84f4 40100461
<<<stack<<<

ets Jan 8 2013,rst cause:2, boot mode:(3,7)

load 0x4010f000, len 1384, room 16
tail 8
chksum 0x2d
csum 0x2d
v8b899c12
~ld

bitte erst selber austesten, wenn du einen Code postest!

Rumgucker
20.11.2019, 12:28
Hmmmm....

Der C++-Compiler berechnet das statische Array völlig korrekt. Aber bein dynamischen Zielarray scheint er nichts zu raffen



;
; for (int j=0; j<30; j++) {
;
?debug L 92
xor cx,cx
jmp short @4@142
@4@86:
;
; arraydyn[i][j]=arrayst[i][j]*123;
;
?debug L 93
mov bx,si
imul bx,bx,60
mov ax,cx
add ax,ax
add bx,ax
lea ax,word ptr [bp-6014]
add bx,ax
mov ax,word ptr ss:[bx]
imul ax,ax,123
mov dx,si
shl dx,2
les bx,dword ptr [bp-4]
add bx,dx
les bx,dword ptr es:[bx]
mov dx,cx
add dx,dx
add bx,dx
mov word ptr es:[bx],ax
?debug L 92
inc cx
@4@142:
cmp cx,30
jl short @4@86


Skandalös ist, dass der Compiler nicht mal ne Warnung oder sowas auslöst.

Ich geh nochmal in mich.

Viele Grüße

Wolfgang

HaWe
20.11.2019, 12:34
genau, jetzt brauchen wir nur noch lauffähigen Code! 8)

bevor du Code postest also bitte vorher selber testen!
(sonst steht hier bald seitenweise Code, der fehlerhaft ist
- das bringt nichts und macht es nur komplett unübersichtlich) ;)

Rumgucker
20.11.2019, 12:34
Hallo Helmut,


bitte erst selber austesten, wenn du einen Code postest!

Bin ich Dein Wasserträger?

Ich bau mir jetzt ganz bestimmt keine Entwicklungsumgebung.

Du hast mich nach der Kodierbarkeit gefragt und 2-dimensionale Arrays gefordert. Warum auch immer.

Ich hab Dir was geliefert, was der Compiler schluckt. Obs läuft, musst Du schon selbst testen. Und das macht Dir ja auch keine Mühe, weil Du die drei Zeilen ja nur einzuklicken brauchst.

Ich zieh mich hier mal zurück. Mir fällt eh nichts mehr ein.


Viele Grüße

Wolfgang

HaWe
20.11.2019, 12:36
es läuft ja nicht, weil dein Code bisher fehlerhaft ist - du könntest ja auf anderen Plattformen testen

Rumgucker
20.11.2019, 12:49
Hallo Helmut,

ich könnte vieles. Bereit war ich aber nur zum Mitdenken.

Viele Grüße

Wolfgang

HaWe
20.11.2019, 13:04
danke, aber es wird ja korrekter lauffähiger, C++ konformer Code benötigt.


edit:
habe noch einen anderen Tipp bekommen, das hier hat bis jetzt anscheinend funktioniert - ich teste es aber noch weiter:

float array2D[LINE][COL]; // statisch im stack

float (*arraydyn)[COL] = new float[LINE][COL]; // dynamisch auf dem heap

Sisor
23.11.2019, 15:43
Nur so nebenbei: line und row sind Synonyme.

HaWe
23.11.2019, 22:39
ich gebrauche für meine Zwecke line für waagerechte Linien und row für senkrechte Reihen zur Unterscheidung, es mag aber bessere Bezeichner geben.
Was schlägst du für senkecht vor? Ist column besser?

Sisor
23.11.2019, 23:57
Im Englischen werden für Matrizen normalerweise row und column (dt.: Zeile und Spalte) verwendet: array[ROWS][COLUMNS].
In der Mathematik wird eigentlich immer m und n benutzt; das ist sprachunabhängig und würde im Code zu matrix[M][N].

HaWe
24.11.2019, 08:22
Im Englischen werden für Matrizen normalerweise row und column (dt.: Zeile und Spalte) verwendet: array[ROWS][COLUMNS].
In der Mathematik wird eigentlich immer m und n benutzt; das ist sprachunabhängig und würde im Code zu matrix[M][N].

ok, danke, werde ich künftig auch so machen.
Meist verwende ich ja gamz andere Indizes (Y, X, MAXIN, MAXNUM), hier sollte es nur zeigen, wie in welcher Reihenfolge was wo stehen muss, damit man die Überkreuz-Deklaration mit new() nicht falsch herum macht. Damit es klarer ist, werde ich oben schon mal ROW durch COL ersetzen, danke!