Hallo und Frohe Weihnachten, ich kämpfe mal wieder mit den Zeiger in C und der Syntax. Weiss zwar was ich will aber nicht wie ich das dem Compiler begreiflich machen soll. Ich habe zwei Felder, die ich aus lauter Not schon in einen Struct zusammengefasst habe: Typdefintion struct feld_type { char last[MAX_X+1][MAX_Y+1]; char next[MAX_X+1][MAX_Y+1]; }; Funktion 2 { muss feld bearbeiten } Funktion 1 (Feldübergabe) { Funktion 2 (Feld durchreichen) } später in main() void main(void) { struct feld_type feld; ..... Funktion_1(Feldübergabe) ... } Nun ist aber noch Funktion 1 Aufrufer von Funktion 2 und auch Funktion 2 braucht das Feld zum Bearbeiten, d.h. es muss nochmal durchgereicht werden. An dem trip ohne struct, also Zeiger auf mehrdimensionale Arrays zu übergeben bin ich gescheitert, keine Ahnung ob void* oder void**, ob &feld[0] oder &feld[0][0] oder nur &feld. Daher wollte ich den struct drumherum lassen Könnte das mal jemand mit Beispiel gut verständlich erklären wie ich die beiden Felder im struct durchreiche (keine Kopie!).
Müsste so gehen.
1 | typedef struct _feld_t |
2 | { |
3 | char last[MAX_X+1][MAX_Y+1]; |
4 | char next[MAX_X+1][MAX_Y+1]; |
5 | }feld_t; |
6 | |
7 | |
8 | Funktion_2 (feld_t* pFeld) |
9 | { |
10 | z=pFeld->last[x][y]; |
11 | } |
12 | |
13 | Funktion 1 (feld_t* pFeld) |
14 | { |
15 | Funktion_2(pFeld); //Pointer übergeben |
16 | } |
17 | |
18 | void main(void) |
19 | { |
20 | feld_t feld; |
21 | |
22 | |
23 | Funktion_1(&feld); //Adresse von "feld" übergeben |
24 | } |
:
Bearbeitet durch User
Bingo! Läuft durch und ergibt das richtige! Allerdings bläst sich mein Stack jetzt gewaltig auf wegen der dynamischen Speicherallokation durch die Arrays und nähert sich bedrohlich nahe dem Code Ende. Ist bei mir ehg so ne Frage: Was ist besser? Speicher vom Stack holen? Speicher vom Heap holen? Oder globale Vars hier verwenden, die dann im Datensegment erzeugt werden, statt auf dem Stack? Ist dem Mikrocontroller nämlich wumpe, der hat nur 40k und wie man die aufteilt ist dem egal.
Christian J. schrieb: > Ist bei mir ehg so ne Frage: Was ist besser? Speicher vom Stack > holen? Speicher vom Heap holen? Oder globale Vars hier verwenden, > die dann im Datensegment erzeugt werden, statt auf dem Stack? Ist > dem Mikrocontroller nämlich wumpe, der hat nur 40k und wie man die > aufteilt ist dem egal. Damit beantwortest du die Frage ja schon selbst. Wie du deine Arrays anlegst, ist "wumpe", denn sie werden durch andere Art des Anlegens nicht plötzlich weniger Platz brauchen. Einzig das dynamische Erzeugen braucht ein paar Bytes mehr Platz, da die dazugehörigen Verwaltungsinformationen noch irgendwo gespeichert werden müssen.
:
Bearbeitet durch User
Was würdest du denn als "geschwindigkeitsoptimale" Lösung sehen? Ich codiere grad aus Spass "Game of Life" auf einem 4 Mhz Z80 und da ist es nunmal etwas langsamer unterwegs. Würdest du cell_status eleminieren und in den Aufrufer rein packen? Der Code wird dadurch etwas schwerer lesbar aber die Funktion wird nur einmal aufgerufen von einem einzigen Aufrufer.m Unterschied beim Kompileren sind nur 20 Bytes mehr, wenn es eine einzelne Funktion bleibt. Im Kommentarfeld ist die Funktion einzeln reinkopiert, d.h. sie kann gelöscht werden. / Berechne den neue Zellstatus static enum cell_stat cell_status(struct feld_t *feld, char xpos, char ypos) { char y,x; uint8_t livecells; // Zustand der 8 Nachbarn livecells = 0; // Ermittle den Zustand der 8 Nachbarn for (y = ypos-1;y <= (ypos+1);y++) { for(x = xpos-1;x <= (xpos+1);x++) if (feld->last[x][y] == ALIVE) if (++livecells > 4) return (DEAD); } // Sich selbst als Nachbar abziehen if (feld->last[xpos][ypos] == ALIVE) livecells--; // Lebt + 2 Nachbarn = lebt weiter, Tot/Lebt + 3 Nachbarn = Lebt (wieder) return((feld->last[xpos][ypos] && (livecells == 2)) || (livecells == 3)); } // Berechne die nächste Generation uint16_t calc_nextgen(struct feld_t *feld) { uint8_t x,y,ypos,xpos; uint16_t mods; uint8_t livecells; // Zustand der 8 Nachbarn mods = 0; n_cells = 0; // Raender des Feldes nicht betrachten for (y=1;y < MAX_Y;y++) { for (x=1;x < MAX_X;x++) { // Berechne neuen Status einer Zelle feld->next[x][y] = cell_status(feld, x,y); /* // Ermittle den Zustand der 8 Nachbarn livecells = 0; for (ypos = y-1;ypos <= (y+1);ypos++) { for(xpos = x-1;xpos <= (x+1);xpos++) if (feld->last[xpos][ypos] == ALIVE) livecells++; } // Sich selbst als Nachbar abziehen if (feld->last[x][y] == ALIVE) livecells--; // Lebt + 2 Nachbarn = lebt weiter, Tot/Lebt + 3 Nachbarn = Lebt (wieder) feld->next[x][y] = (feld->last[x][y] && (livecells == 2)) || (livecells == 3); */ // Lebende Zellen zaehlen if (feld->next[x][y]==ALIVE) n_cells++; // Bei Veränderung neu zeichnen if (feld->next[x][y] != feld->last[x][y]) { move(MAX_Y-y,x); if (feld->next[x][y] == ALIVE) addch('O'); else addch(' '); mods++; } } } // Altes Feld = Neues Feld memcpy(feld->last,feld->next,sizeof(feld->next)); // Anzahl Veränderungen zurück return (mods); }
Evtl. mal das komplette Programm posten.
Wumpe schrieb: > Evtl. mal das komplette Programm posten. Hat sich schon erledigt.... es ist effizienter aus allem eine Funktion zu machen, da der Übergabekram wegfällt. Das war übrigens der ganze Code.
Christian J. schrieb: > Das war übrigens der ganze Code. Ich hatte den anderen Thread nicht gesehen.
Wumpe schrieb: > Christian J. schrieb: >> Das war übrigens der ganze Code. > > Ich hatte den anderen Thread nicht gesehen. Weisst Du trotzdem vielleicht wie man mehrdim Array als Zeiger übergibt? Kommt vielleicht bald mal wieder vor. Die Kapselung in einen Struct, nur weil ich nicht wusste wie es sonst geht ist ja sicher keine Dauerlösung sondern nur aus der Not geboren.
1 | void foo(char *pArray) |
2 | {
|
3 | char x = 4; |
4 | char y = 5; |
5 | //grenzen von array überprüfen
|
6 | pArray[x][y]; |
7 | }
|
8 | char last[MAX_X+1][MAX_Y+1]; |
9 | |
10 | foo(last); |
Der Compiler weiss aus dem Zeigertyp (hier: zeiger auf typ char) wie die Adressen im arras zu inkrementieren sind.
icke schrieb: > Der Compiler weiss aus dem Zeigertyp (hier: zeiger auf typ char) wie die > Adressen im arras zu inkrementieren sind. Das ist so nicht kompilierbar. Gleich 2 Fehlermeldungen im Aufruf und der Funktion.
1 | void foo(char (*par)[20]) |
2 | {
|
3 | /*...*/
|
4 | par[9][19] = 42; |
5 | /*...*/
|
6 | }
|
7 | |
8 | void bar() |
9 | {
|
10 | char a[10][20]; |
11 | foo(a); |
12 | }
|
http://ideone.com/AEohFt
Christian J. schrieb: > Weisst Du trotzdem vielleicht wie man mehrdim Array als Zeiger übergibt? > Kommt vielleicht bald mal wieder vor. Weitaus besser ist es, sich erst einmal klarzumachen, daß es in C keine mehrdimensionalen Felder gibt - und so etwas künftig besser zu vermeiden. Rate mal, was der Ausdruck char x[a][b]; eigentlich beinhaltet. x ist nämlich ein Array von Zeigern, die jeweils auf ein Array von Chars zeigen. Es ist eben KEIN mehrdimensionales Feld von Chars. Wenn du das verstanden hast, dann wird dir damit auch klar, was du mit deinem Versuch unter der Decke des Compilers eigentlich anrichtest. Man kann das tun, aber es ist nicht wirklich das Beste. mein Vorschlag: arbeite lieber mit eindimensionalen Feldern und adressiere dort per Berechnung, also eher #define am 100 #define bm 50 char x[am*bm]; und if (x[12+34*bm]==125) blabla(); W.S.
W.S. schrieb: > Rate mal, was der Ausdruck > char x[a][b]; > eigentlich beinhaltet. > x ist nämlich ein Array von Zeigern, die jeweils auf ein Array von Chars > zeigen. Das ist nicht wahr. x ist ein Array von a Arrays von b chars. Keine Zeiger weit und breit.
Christian J. schrieb: > Ist dem > Mikrocontroller nämlich wumpe, der hat nur 40k Christian J. schrieb: > Ich > codiere grad aus Spass "Game of Life" auf einem 4 Mhz Z80 Dann wäre die allererste Massnahme, nicht char sondern einzelne Bits zu verwenden - das reduziert den Speicherbedarf schon mal um den Faktor 8. Dann muss man die Zugriffe sowieso neu überdenken. Und was die Geschwindigkeit angeht, für die Überprüfung einer Zelle wäre eine Assemblerfunktion unschlagbar schnell. Besonders wenn die Arraygrössen 2er Potenzen sind. Georg
Georg schrieb: > Dann wäre die allererste Massnahme, nicht char sondern einzelne Bits 64kb sollten genug sein... und Bits mag er nicht, eher Bytes, dafür ist der Befehlssatz ausgelegt worden. Inline Asm hat leider das problem, dass du nicht auf die lokalen Vars zugreifen kannst, weil niemand weiss wie die im Stack grad liegen. Alptraum sich mit dem Frame Pointer anzulegen..... Die Idee mit dem 1D Feld werde ich mal angehen, erfordert dann nur Hirnschmalz sich das Ganze trotzdem 2D vorzustellen, 2D Array war so schön einfach das zu kodieren.
Der hier codiert es allerdings auch 2D: https://www.pdc.kth.se/education/tutorials/summer-school/mpi-exercises/mpi-lab-codes/game_of_life-serial.c/view und viele andere Beispiele auch..
Christian J. schrieb: > und Bits mag er nicht, eher Bytes, dafür ist > der Befehlssatz ausgelegt worden. Wenn das alles ist was du über den Z80 weisst ist dir nicht zu helfen. Georg
Georg schrieb: > Wenn das alles ist was du über den Z80 weisst ist dir nicht zu helfen. Ich möchte das aber nicht in Bits codieren, da ich einen C Compiler verwende und keinen Assembler, ok?
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.