Forum: PC-Programmierung Mehdimensionale Arrays als Pointer an Funktion übergeben


von Christian J. (Gast)


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!).

von Detlef K. (adenin)


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
}

: Bearbeitet durch User
von Christian J. (Gast)


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.

von Rolf M. (rmagnus)


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.

: Bearbeitet durch User
von Christian J. (Gast)


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);
}

von Wumpe (Gast)


Lesenswert?

Evtl. mal das komplette Programm posten.

von Christian J. (Gast)


Lesenswert?

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.

von Wumpe (Gast)


Lesenswert?

Christian J. schrieb:
> Das war übrigens der ganze Code.

Ich hatte den anderen Thread nicht gesehen.

von Christian J. (Gast)


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.

von icke (Gast)


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.

von Christian J. (Gast)


Lesenswert?

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.

von Heiner Heinersen (Gast)


Lesenswert?

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

von W.S. (Gast)


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.

von Heiner Heinersen (Gast)


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.

von Georg (Gast)


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

von Christian J. (Gast)


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.

von Christian J. (Gast)


Lesenswert?

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..

von Georg (Gast)


Lesenswert?

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

von Christian J. (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.