Mehdimensionale Arrays als Pointer an Funktion übergeben

Gast #3937877
Lesenswert?
• ▲
▼
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!).
#3937884
Lesenswert?
• ▲
▼
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
}
Gast #3937890
Lesenswert?
• ▲
▼
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.
#3937897
Lesenswert?
• ▲
▼
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.
Gast #3937903
Lesenswert?
• ▲
▼
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);
}
Gast #3939390
Lesenswert?
• ▲
▼
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.
Gast #3939433
Lesenswert?
• ▲
▼
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.
Gast #3940267
Lesenswert?
• ▲
▼
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.
Gast #3940274
Lesenswert?
• ▲
▼
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.
Gast #3940316
Lesenswert?
• ▲
▼
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
Gast #3940346
Lesenswert?
• ▲
▼
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren