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!).
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.
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);
}
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.
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.
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.
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 40kChristian 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.
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?