Zweidimensionales Array
-
Hallo,
warum funktioniert das nicht?
#include <stdio.h> #include <stdlib.h> void foo(int** m) { int a = m[0][0]; } int main(void) { int A[2][2] = {{1,1},{2,2}}; matrix(A); }
cannot convert ‘int (*)[2]’ to ‘int**’
danke
-
ups...schreibfehler. In der main steht natürlich
foo(A);
-
Weil ein Array kein Zeiger ist. Das wird oft falsch gemacht und hier kracht es dann. Zwar kann A (welches vom Typ int[2][2] ist) implizit in ein
int (*)[2]
umgewandelt werden (Array to pointer decay, man erhält einen Zeiger auf das erste Element), aber ein Zeiger auf ein int[2] ist eben etwas ganz anderes als ein Zeiger auf einen Zeiger auf int. Schließlich zeigt der eine auf einen int[2], der andere auf einen Zeiger. Wie soll das konvertiert werden und immer noch funktionieren? Stell dir mal vor, jemand wandelt das mit einem Cast mit Gewalt um und würde den so erhaltenen Zeiger dereferenzieren. Dann würde man den Inhalt des int[2] als Zeigerwert auffassen. Bumm!
Beschreib mal genau, was du erreichen möchtest, dann kann man auch beschreiben, wie eine gute Lösung aussehen könnte.
edit: Technischer Hintergrund:
Speicherlayout eines int[2][2]:------------------------------------- | [0][0] | [0][1] | [1][0] | [1][1] | -------------------------------------
Speicherlayout eines int**, der auf 2x2-Elemente zeigt:
--------- | int** | --------- | --------- | v ---------------- | [0] | [1] | ---------------- | | -------- ---------------- | | v v ------------------- ------------------- | [0][0] | [0][1] | | [1][0] | [1][1] | ------------------- -------------------
So sollte klar sein, wie groß die Unterschiede sind und wieso das daher nicht zueinander passt.
-
Wow, vielen Dank für die Erkläung
Ich möchte einfach in der Methode auf die Arrayelemente zugreifen, zum Beipiel um es auszugeben. Wie muss ich es denn machen?
SeppJ schrieb:
--------- | int** | --------- | --------- | v ---------------- | [0] | [1] | ---------------- | | -------- ---------------- | | v v ------------------- ------------------- | [0][0] | [0][1] | | [1][0] | [1][1] | ------------------- -------------------
So sollte klar sein, wie groß die Unterschiede sind und wieso das daher nicht zueinander passt.
Was genau ist das Array 0, 1 (in der Mitte) auf das int** zeigt?
-
Das sind Zeiger auf die Startadressen für die zwei Listen mit Ints, deswegen Zeiger() auf Zeiger() auf Ints(int), von rechts gelesen.
-
und was muss ich machen, wenn in der Mitte drei Zeiger stehen sollen? Etwa drei Sterne?
Wie sähe denn der Code aus, um ein zweidimensionales Array per Zeiger zu übergeben?
Vielen Dank
-
2d schrieb:
und was muss ich machen, wenn in der Mitte drei Zeiger stehen sollen? Etwa drei Sterne?
Das gleiche, bloß eine Ebene weiter getrieben. Aber: Hör auf
Es gibt da sogar ein Schimpfwort für: Drei-Sterne-Programmierer
Google: three star programmer
Mangelnde Abstraktion ist die Krankheitsursache.Wie sähe denn der Code aus, um ein zweidimensionales Array per Zeiger zu übergeben?
Entweder
void foo(int *bar[5])
wenn die innere Dimension fest und bekannt ist (hier: 5) oder
void foo(int *bar, int N)
wenn die innere Dimension flexibel sein muss. Dann musst du dir die Indizes eben selber ausrechnen. Außerdem musst du einen Zeiger auf das erste int-Element (oder natürlcih den passenden Datentyp, int ist nur ein Beispiel) übergeben, anstatt einen Zeiger auf das innere Array.
In beiden Fällen willst du natürlich oftmals noch die Größe des äußeren Arrays ebenfalls übergeben. Das habe ich hier nicht gezeigt.
Oder die Alternative, da ich oben Abstraktion ansprach: Du kapselst so weit wie möglich in structs, so dass man die Arrays gar nicht mehr sieht. Für jede Kapselungsebene kannst du dir einen Stern sparen. Zwei Sterne sind noch gerade so ok, aber drei ist wirklich zu viel.
-
Ok, vielen Dank für deine Erklärung. Eine Sache ist mir noch nicht klar. Wenn ich
void foo(int* arr, int n){};
ein zweidimensionales Array übergeben möchte, warum muss ich dann foo(*arr,x); schreiben, also mit Stern? Bei einem eindimensionalen Array ist dies nicht nötig.
-
Weil
int arr[2][2];
durch array to pointer decay höchstens einint (*)[2]
wird, wie oben erklärt. Das wäre der passende Typ für die andere Variante mit der festen Dimension des inneren Arrays.*arr
ist aber das gleiche wiearr[0]
also einint[2]
. Der zerfällt in einenint*
, passt also zur Funktionssignatur. Alternativen wären nocharr[0]
,&arr[0][0]
oder, weniger schön,(int*) arr
.P.S.: Möglichst nicht raten beim Programmieren. Wenn etwas nicht funktioniert: Nachdenken! Nicht so lange *, & oder Casts in den Code einfügen, bis es zufällig compiliert. Es compiliert nämlich auch jede Menge Code, der absoluter Unsinn ist. Man sollte daher schon genau wissen, was man tut.