int **x, int *x[] und int x[][]
-
Hallo,
ich habe immer angenommen, dass
int **x; und int *x[]; und int x[][];
immer das selbe bedeutet;
so als würden die eckigen Klammern nur den Pointer ersetzen.
Das stimmt ja aber doch nicht, oder?
Könnte mir das vielleicht jemand erklären?mfg DerUnterschied
-
int** x; // <- Pointer auf einen Pointer auf einen int int* x[]; // <- Array unbestimmter Größe aus Pointern auf int int x[][]; // <- error, nur die letzte Ebene kann unbestimmte Größe haben
-
Danke dot.
Was würde
int ***x;
dann für ein Sinn machen? Vor deiner Antwort habe ich gedacht, dies sei 1zu1 das selbe wie int x[][][];
Nach deiner Erklärung ist es aber ein
Pointer -> Pointer -> Pointer -> int.
Die ersten "zwei Ebenen" zeigen dabei doch auch wieder nur auf ein Pointer.
"Die int-Adresse eines Pointers der auf ein Pointer" zeigt müsste doch aber genau so groß sein wie "die int-Adresse eines Pointers der auf ein Pointer zeigt der wiederrum auf ein Pointer zeigt".
Also sizeof(**int) == sizeof(*int);
Demnach müsste doch auch int *x == int **x; sein?Egal wie viele * ich noch vor die Variable packe:
x zeigt immer noch auf ein Pointer (sofern * > 2).int ***x;
und
int **y, *x;
x = &y;ist das selbe?
Wenn also das * keine gleichbedeutende Alternative zu [] ist:
Warum sieht man ab und an so eine schreibweiße wie int ***foo; ?Ich hoffe, man versteht was ich meine.
-
Worauf ich zudem hinaus möchte:
Egal wie viele * ich noch vor die Variable packe:
x zeigt immer noch auf ein Pointer (sofern * > 2).Die benötigte Speichergröße bleibt doch konstant?
-
Ich denk, all deine Verwirrung stammt daher, dass du dem weit verbreiteten Irrglauben unterliegst, dass Arrays irgendwie nichts anderes seien als Pointer. Dem ist aber ganz und gar nicht so. Einfacher Beweis:
int* a; int b[12]; std::cout << sizeof(a) << " vs. " << sizeof(b) << '\n';
a
in diesem Beispiel ist ein Pointer auf einenint
.b
dagegen ist ein Array aus 12int
s.b
ist nicht nur ein Zeiger auf einen Speicherbereich, der 12int
s enthält.b
ist der Speicherbereich.b
kann lediglich implizit in einen Pointer auf den erstenint
im Array konvertiert werden, wenn es in einem Kontext verwendet wird, der einen Pointer erfordert.DerUnterschied schrieb:
Was würde
int ***x;
dann für ein Sinn machen? Vor deiner Antwort habe ich gedacht, dies sei 1zu1 das selbe wie int x[][][];
Nach deiner Erklärung ist es aber ein
Pointer -> Pointer -> Pointer -> int.Ganz genau das ist es auch.
DerUnterschied schrieb:
Wenn also das * keine gleichbedeutende Alternative zu [] ist:
Warum sieht man ab und an so eine schreibweiße wie int ***foo; ?Wenn
foo
ein Array ist, kann es in einen Pointer sein erstes Element konvertiert werden.*foo
wäre dann das erste Element des Arraysfoo
. Wennfoo
ein Array aus einem Array ist – und z.B.int x[3][4]
ist nichts anderes als ein Array aus 4 Arrays aus 3int
s) – dann zeigt*foo
auf das erste Element des Arrays, welches selbst wiederum ein Array ist und in einen Zeiger auf sein erstes Element konvertiert werden kann.**foo
zeigt dann auf das erste Element des ersten Elements usw. All das funktioniert nur, weil die Arrays, mit denen du arbeitest, überall implizit in Zeiger auf ihre ersten Elemente konvertiert werden. Dabei wird ein temporärer Zeiger erstellt, der auf das erste Element zeigt. Das jeweilige Array selbst ist und bleibt ein Array und kein Pointer...
-
Welche Ausgabe ich da erhalte war mir auch klar.
Irgendwie hat es aber immer noch nicht "klick" gemacht.Kannst du mir sagen wann ich eine Funktion so aufbaue:
int foo(int *a);
und wann so:
int[] bar(int a[]);
?
int x = { 1, 2, 3 }; foo(&x); bar(x);
Die eine könnte ein Call by reference werden, die andere ein Call by value. Ok.
Ach, vielleicht sollte ich auch mehr programmieren statt mich soviel mit der Theorie zu beschäftigen. Womöglich wird es mir dadurch klarer.
Danke jedenfalls schonmal für deine Hilfe
PS: std::cout ... @ C (C89, C99 und C11)
-
Das Problem mit Funktionen ist, dass es in C und C++ arkane Regeln gibt, die besagen, dass Arraydeklarationen in der Deklaration einer Parameterliste einer Funktion keine Arrays deklarieren, sondern Pointer (genaugenommen werden die Deklarationen vom Compiler angepasst). Wenn du schreibst
void f(int x[])
, dann ist das erste, was der Compiler macht, wenn er diese Deklaration sieht, dass er sie umwandelt invoid f(int* x)
.void f(int x[]); void f(int* x);
deklariert also zweimal die selbe Funktion. Das liegt aber nicht daran, dass
int x[]
das gleiche wäre wieint* x
, sondern daran, dass der Compiler in diesem Fall still und heimlich deinen Code umschreibt. Der Effekt davon ist, dass es so aussieht, als ob Arrays in C, im Gegensatz zu allen anderen Typen, "by Reference" übergeben würden; denn wenn du diese Funktion nun mit einem Array aufrufst, wird das Array implizit in einen Pointer auf das erste Element umgewandelt, da der erste Parameter der Funktion ja ein Zeiger ist.Zusammenfassung: Pure Arrays sind in C wahrlich merkwürdige Gebilde, die auf den ersten Blick vielleicht anmutig und zahm erscheinen mögen, in Wahrheit aber teilweise extrem obskuren Regeln folgen. Wenn du C++ nutzen würdest, würde ich an dieser Stelle empfehlen, std::array zu verwenden, denn das verhält sich – im Gegensatz zu puren Arrays – so, wie man es intuitiv erwarten würde. So empfehle ich halt einfach, C++ zu verwenden...
Btw: Eine Funktion kann kein Array als Rückgabewert haben.
-
Hehe.
Danke für deine Erklärungen.
Ich denke, mir ist einiges klarer geworden