Zweidimensionales Array an Funktion übergeben



  • Hallo,
    ich habe hier ein kleines Verständnisproblem mit Pointern auf zweidimensionale Arrays.

    Bei Eindimensionalen Arrays habe ich einen Pointer auf das Array der Funktion übergeben und dann die Adresse immer weiter erhöht, um die Elemente anzusprechen.

    Nun habe ich ein zweidimensionales Array; hier habe ich ja quasi einen Pointer auf einen Pointer.

    Um auf die Elemente zuzugreifen habe ich mir das folgendermaßen gedacht:

    int conway_table[8][8] = { 0 };
    int i;
    
    i = *(*(conway_table + z) + s); // Element der z-ten Zeile und s-ten Spalte
    

    Das funktioniert soweit auch.
    Nun wollte ich das ganze einer Funktion übergeben.

    Nun dachte ich mir das folgendermaßen. Ich übergebe der Funktion den Pointer auf das Array und arbeite dann wie gewohnt:

    int conway_table[8][8] = { 0 };
    int i;
    
    void tuwas(int **ctable)
    {
       i = *(*(ctable + z) + s);
    }
    
    void main()
    {
       tuwas(conway_table);
       return;
    }
    

    Das scheint wiederum so nicht zu funktionieren. 😞 Könnt Ihr mir helfen?
    Die Funktion sollte Arrays beliebiger quadratischer Größe annehmen können.

    Viele Grüße

    Dominik



  • DMG schrieb:

    Nun habe ich ein zweidimensionales Array; hier habe ich ja quasi einen Pointer auf einen Pointer.

    Nein.
    Ein echtes 2D-Array (so wie du es benutzt) ist auch nur ein einfacher Pointer.
    Das ist ein Zusammenhängender Speicherbereich.

    int conway_table[ZEILEN][SPALTEN] = { 0 };
    int i;
    
    void tuwas(int *ctable)
    {
       i = ctable[z*SPALTEN+s];
    }
    
    // oder allgemeiner für beliebige Größen:
    void tuetwas(int *ctable, int breite)
    {
       i = ctable[z*breite+s];
    }
    


  • DMG schrieb:

    Bei Eindimensionalen Arrays habe ich einen Pointer auf das Array der Funktion übergeben und dann die Adresse immer weiter erhöht, um die Elemente anzusprechen.

    Nein, du hast einen Pointer auf das erste Element übergeben. Der Wert ist gleich, der Datentyp nicht.

    Nun habe ich ein zweidimensionales Array; hier habe ich ja quasi einen Pointer auf einen Pointer.

    Nein, du hast auch hier einen Pointer auf das erste Element. Ein zweidimensionales Array ist nichts anderes als ein Array, dessen Elemente Arrays sind ... der Pointer auf das erste Element ist also ein Pointer auf ein (eindimensionales) Array.

    Und im Unterschied zum eindimensionalen Array ist es nicht nur eine Frage der Denkweise oder des Datentyps, es liegt effektiv kein Pointer auf einen Pointer vor.

    Um auf die Elemente zuzugreifen habe ich mir das folgendermaßen gedacht:

    int conway_table[8][8] = { 0 };
    int i;
    
    i = *(*(conway_table + z) + s); // Element der z-ten Zeile und s-ten Spalte
    

    Oder conway_table[z][s], aber warum einfach wenn's auch kompliziert geht.

    Das scheint wiederum so nicht zu funktionieren. 😞 Könnt Ihr mir helfen?
    Die Funktion sollte Arrays beliebiger quadratischer Größe annehmen können.

    Bei variablen Dimensionen hast du durch das Typsystem keine Unterstützung mehr, die einzige Chance ist, das Array als eindimensionales Array zu interpretieren und die Indizes selbst auszurechnen:

    void tuwas(int *ctable, int size)
    {
       i = ctable[z * size + s];
    }
    


  • Oder conway_table[z][s], aber warum einfach wenn's auch kompliziert geht.

    Das stimmt wohl 😉 Hatte es nur auf diese Weise probiert, um zu überlegen, wie es in der Funktion aussieht.

    Ein echtes 2D-Array (so wie du es benutzt) ist auch nur ein einfacher Pointer.

    Ok, Danke. Dann hatte ich mir das falsch vorgestellt/gedacht.

    Das ist ein Zusammenhängender Speicherbereich.

    Komischerweise, war mir das wiederum klar; hatte nur gedacht, dass es doch auch über Zeilen- und Spaltenauswahl gehen muss.

    Dieser Ansatz funktioniert aber auf Grund dessen nicht, da es trotzdem nur einen Pointer gibt, der zunächst auf den Anfang des Arrays zeigt. Ist das Korrekt?

    Wenn ich das und eure Beispiele jetzt richtig verstanden habe, muss ich um in die "nächste Zeile zu kommen" (bzw. in den Adressbereich, der die nächste Zeile beinhaltet), immer die Spaltendimension kennen, um die ersten s Elemente (bei s Spalten) zu überspringen.

    Super! Vielen Dank!

    Das finde ich logisch und verständlich. Was mich jetzt aber noch etwas stört, warum dann das hier funktioniert?

    i = *(*(conway_table + z) + s); // Element der z-ten Zeile und s-ten Spalte
    

  • Mod

    DMG schrieb:

    Was mich jetzt aber noch etwas stört, warum dann das hier funktioniert?

    i = *(*(conway_table + z) + s); // Element der z-ten Zeile und s-ten Spalte
    

    Warum nicht? Es ist exakt das gleiche wie conway_table[z][s].

    (P.S.: Hier spielt natürlich auch wieder eine Rolle, dass
    1. Ein Array in einen Zeiger auf sein erstes Element zerfällt.
    2. Hier ein Array von Arrays vorliegt.
    Daher hat man erst einmal beim Ausdruck (conway_table + z) einen Zeiger auf das erste innere Array. Dieser Zeiger ist vom Typ Zeiger auf ein Array von der Größe des inneren Arrays! Daher gibt einem conway_table + z als Ergebnis einen Zeiger auf das z'te innere Array. Der wird dann dereferenziert, so dass man das innere Array selber bekommt, also:

    *((z'tes inneres Array) + s);
    

    Dann geht das gleiche Spielchen nochmal los. Das z'te innere Array wird im Rahmen der Addition zu einem Zeiger auf sein erstes Element, so dass man insgesamt das s'te Element des z'ten Arrays bekommt.)

    Der Operator [] ist nur eine Abkürzung für die Addition und Dereferenzierung.

    foo[x];
    *(foo + x);
    

    Ist beides genau das gleiche. Damit einem das wirklich deutlich wird, kann man das sogar noch eine Stufe weiter treiben:
    Da Addition zu einem Pointer assoziativ ist, ist obiges auch das gleiche wie

    *(x + foo);
    

    Und somit auch das gleiche wie:

    x[foo];
    

    Wenn man das mal in einem richtigen Programm tut, stellt man fest, dass das wirklich geht:

    int array[] = {1, 2, 3};
      int zwei = 2;
    
      printf("%d = %d = %d = %d\n", array[2], array[zwei], zwei[array], 2[array]);
    
      // Zeichenkettenliterale sind auch nur Arrays:
      printf("%c = %c = %c = %c\n", "foo"[2], "foo"[zwei], zwei["foo"], 2["foo"]);
    

    Ist halt nur ein bisschen unleserlich 🙂 , daher nicht in Produktivcode zu empfehlen.



  • Super Erklärung!

    Vielen Dank!


Log in to reply