[Mehrdimensionale Arrays]Frage zu Satz aus Lehrbuch
-
oenone schrieb:
Mr.Long schrieb:
int ia[2][4];
ist das selbe wie
int ia[2*4];
Bei Letzterem sind die ints aneinanderhängend. Bei Ersterem ist das nicht unbedingt der Fall.
Erste Fall: ia zeigt auf einen Speicherbereich, an dem nacheinander zwei Adressen von int[4] liegen. Diese können (theoretisch) weit voneinander entfernt sein. Du musst also doppelt dereferenzieren, um ein int-Element zu erreichen.
Zweiter Fall: ia zeigt auf einen Speicherbereich, an dem nacheinander acht int liegen. Du musst nur einmal dereferenzieren, um ein int-Element zu erreichen.
Nicht ganz. Das Speicherlayout ist gleich, würde ich meinen.
Du beschreibst gerade sowas wieint ia0[4],ia1[4],*ia[2]={ia0,ia1};
-
Auch bei einem mehrdimensionalen Array liegen die Werte hintereinander im Speicher (im sog. row-major-Format).
-
VieleDimensionen schrieb:
Ich lese momentan das Lehrbuch C++ Primer und bin bei Mehrdimensonalen Arrays angelangt.
Um die Verwirrung komplett zu machen (oder aufzuheben!): Es gibt überhaupt keine mehrdimensionalen Arrays in C++. Man kann aber aus jedem Typ (nur Objekttypen, keine Referenzen oder Funktionen) einen passenden Arraytypen basteln, z.B. int => int[10]; char* => char (*)[10]; etc. Aber eben auch int[20] => int[10][20]. Das ist dann halt ein Array, dessen Elemente wiederum Arrays sind. Absolut nichts besonderes.
(In manchen Sprachen gibt es wirklich mehrdimensionalen Arrays, da schreibt man dann z.B. a[i,j] ... das lässt sich nicht als Verschachtelung eindimensionaler Arrays auffassen.)
(Zum Verständniss:
Vorher wurde ein 2Dimensionales Array namens int ia[3][4] definiert)
Absatz aus dem Buch:
"Wenn ein Ausdruck nur einen Index bereitstellt,ist das Ergebnis das Element,dass das innere Array mit dem betreffenden Zeilenindex bildet.
Damit ruft ia[2] das Array ab,das die letzte Zeile von ia bildet.Abgerufen wird kein Element des Arrays,sondern das Array selbst."Dieser Absatz sollte dir mit der obigen Erklärung nun kein Problem mehr bereiten. So wie
ia
hier für ein Array steht (eins mit 3 Elementen vom Typ int[4]), so stehtia[2]
für ein Array mit 4 Elementen vom Typ int. Nichts besonderes.Wie ist das nun gemeint es wird kein Element des Arrays,sondern das Array selbst abgerufen?
Das Element ist selbst ein Array.
Ist damit die im Zeiger auf das erste Element des Arrays enthaltene Addresse gemeint,oder wie muss ich diesen Satz verstehen?
Du solltest zuerst verstehen, was ein Array überhaupt ist, bevor du dir über Adressen Gedanken machst. Denn ob diese Adresse eine Bedeutung hat, hängt davon ab, was du mit dem Array machst. Freilich gibt es da nicht viel, für das die Adresse nicht benötigt wird. Aber das ist trotzdem erst der zweite Schritt.
-
Sowas hab ich zwar noch nie gesehehen, aber es klappt und zeigt, daß der Compiler auch der Meinung ist, daß ia[1] ein Array ist, das vier ints enthält.
#include <iostream> using namespace std; int main() { int ia[2][4]={{2,3,5,7},{11,13,17,19}}; for(auto i:ia[1]) cout<<i<<' '; }
-
volkard schrieb:
Mr.Long schrieb:
int ia[2][4];
ist das selbe wie
int ia[2*4];
Nein.
int ia[2][4];
sagt: ia ist ein Array von 2 Arrays von 4 ints.
Aber
int ia[2*4];
sagt: ia ist ein Array von 8 ints.
Habe ich den unterschied nicht beschrieben?
Aber da wir schon wieder vom Wesentlichen abweichen, revidiere ich natürlich meine Aussage: ist ähnlich wie (man kann es sich so gut merken)
-
Erstmal danke an alle für die bisherigen Antworten.
Was ein Array ist habe ich denke ich schon verstanden daran liegt es nicht:Definiere ich ein normales Array wird mir ein Pointer auf die Adresse des ersten Elements zurückgegeben.Diese Adresse kann ich mit dem Indexoperator/oder einem zweiten Pointer auf das Array z.B. um 1 inkrementieren um auf die nächste Adresse des Arrays zu stoßen.
So wie ich Zweidimensionale Arrays in C++ verstanden habe:
Sagen wir es gibt das Array int arr[3][4] es werden also 12 hinternanderfolgende Adressen für das Array reserviert (Der Speicherpool).
Intern wird das zweidimensionale Array exakt wie ein ein ganz normales Array behandelt es sieht für den Programmierer nur anders aus.Echte Zweidimensionale Arrays:
So wie ich es verstehe müsste ein echtes 2D Array so aussehen(In C++ gibt es sie nur nicht in dieser Form)
const int a=3,b=4 ;
Bei int arr[a][b] müsste man einen Pointer zurückgegeben bekommen welcher auf
das erste Element von a zeigt.
Das Array a würde aus einem Speicherpool von 3 Adressen bestehen.
Jede dieser 3 Adressen verweist auf einen eigenen Speicherpool welcher jeweils 4 Typen vom Typ int aufnehmen kann.
Bei einem echten Mehrdimensionalen Array würde also so wie ich es verstehe nicht ein zusammenhängender Speicherberreich für 12 Werte freigehalten werden.Zur Frage:
Allerdings muss ich sagen der Satz "Abgerufen wird kein Element des Arrays,sondern das Array selbst." leuchtet mir immernoch nicht ein.
Ein Array ist für mich ein Speicherpool und kein einzelner Typ wie soll ich einen gesamten Speicherpool abfragen?
Das würde ja nur gehen indem ich z.B. die Adresse auf das erste Element des Speicherpools habe und diese dann inkrementiere dadurch würde ich aber wiederrum ein Element des Arrays ansprechen und laut dem Satz aus dem Buch ist das ja eben nicht der Fall.
-
VieleDimensionen schrieb:
Erstmal danke an alle für die bisherigen Antworten.
Was ein Array ist habe ich denke ich schon verstanden daran liegt es nichtSicher? Ein Array ist eine Ansammlung von Elementen desselben Types die direkt aufeinanderfolgend im Speicher liegen.
Wie du siehst kommt in dem Satz das Wort Pointer nicht vor. Ein Pointer hat mit einem Array nichts zu tun. Und ein Array hat mit einem Pointer nichts zu tun. Definierst du ein Array hast du ein Array mit N Elementen. Die Elemente des Arrays sprichst du mit [] und einem Index ( 0 bis N-1 ) an.
Du kannst ein Array einem Pointer zuweisen. Dann geschieht array-to-pointer-decay. Das heißt es wird automatisch ein Zeiger generiert, der auf das erste Element des Arrays zeigt. Auf den Pointer kannst du Zeigerarithmetik anwenden. Und da*(Pointer + i)
Pointer[i]
gleichkommt, kannst du auf deinen Pointer [] und einen Index anwenden. Der Pointer wird dann umIndex*Bytes
verschoben, abhängig vom Datentyp.VieleDimensionen schrieb:
So wie ich Zweidimensionale Arrays in C++ verstanden habe:
Ein 2d Array ist ein Array von Arrays. Wie gesagt liegen alle Elemente eins Arrays direkt hintereinander im Speicher. Wenn ein Element des Arrays ein Array ist, liegen logischerweise alle Arrays direkt hintereinander im Speicher. Bei
int arr[3][4]
werden z.B. 3*4*int-Bytes Speicher direkt hintereinander reserviert (int hat oft 4 Bytes, aber nicht immer. Also 48 Bytes werden reserviert).
Auch ein 2d Array hat nichts mit einem Pointer zu tun. Wenn du ein 2d Array einem Pointer zuweist, passiert wieder array-to-pointer-decay. Es wird also ein Zeiger generiert, der auf das erste Element des Arrays zeigt. Da das Array 2d ist, zeigt der Pointer also auf ein Array.VieleDimensionen schrieb:
Allerdings muss ich sagen der Satz "Abgerufen wird kein Element des Arrays,sondern das Array selbst." leuchtet mir immernoch nicht ein.
Ein Array ist für mich ein Speicherpool und kein einzelner Typ wie soll ich einen gesamten Speicherpool abfragen?Ach da versteckt sich der Übeltäter. Ein Array ist ein Typ. Genauso wie int ein Typ ist. Das musst du unbedingt in deinen Kopf einpflanzen. Ein int ist ein "Fundamentaler Datentyp". Ein Array ist ein "Zusammengesetzter Datentyp (compound type)".
Mal ein paar Beispiele:
int main() { int ar[5] = {}; // Alle Elemente werden mit 0 belegt. int* p = ar; // array-to-pointer decay. ==> Für die Faulen. int* p2 = &ar[0]; // Das ist das, was bei array-to-pointer-decay passiert. ==> Für die Pingeligen. int ar_2d[3][4] = {}; int (*p3)[4] = ar_2d; // array-to-pointer-decay int (*p4)[4] = &ar_2d[0]; // Ohne array-to-pointer-decay // Es gibt noch einige andere Situationen, in denen array-to-pointer-decay stattfindet. int array[5] = {}; *array; // Hier zum Beispiel. Du kannst ein Array nicht dereferenzieren, also muss vorher array-to-pointer-decay stattfinden. *(&array[0]); // Ohne array-to-pointer-decay }
-
@out
Laut dem was ich im buch gelesen habe sind Arrays und Pointer in C++ sehr eng miteinander verknüpft.
Im Buch steht geschrieben,wenn ich int arr[5] definiere und den Namen arr in einem beliebigen Ausdruck z.B. arr[1]=3; verwende wird der Name automatisch in einen Zeiger auf das erste Element des Arrays umgewandelt und dann kann er z.B. mit dem Indexoperator in diesem Fall auf die nächste Adresse gesetzt werden.
Also haben Zeiger und Arrays jawohl doch eine sehr enge Bindung in C++ ,denn man greift nicht direkt durch den Namen auf das Array zu ,sondern der Name des Arrays ist ein Pointer in welchem die Adresse des ersten Elements des Arrays zu finden ist.
Dein letzter Satz ist mir einleuchtend und natürlich hast du Recht ein Vector ist ja auch ein Typ ,von daher muss ein Array das natürlich auch sein.Ich habe grade selbst mal getestet was mit dem Satz gemeint war anhand dieses Codes
#include <iostream> int main() { int a = 1; int arr[3][4]; for (int i = 0; i < 2; ++i){ for (int in = 0; i < 3; ++i) { arr[i][in] = a; ++a; } } std::cout << &arr[2][0] <<std::endl; std::cout << arr[2]; std::cin.get(); return 0; }
Ich denke ich verstehe den Satz aus dem Buch nun.
Es wird die selbe Adresse ausgegeben also greife ich mit arr[2] auf die erste Adresse der dritten Zeile des Arrays zu und nicht auf den Wert selbst der in diesem Array liegt.
-
Hatte noch nen dummen Fehler drinne sollte natürlich so aussehen:
#include <iostream> int main() { int a = 1; int arr[3][4]; for (int i = 0; i <= 2; ++i){ for (int in = 0; in <= 3; ++in) { arr[i][in] = a; std::cout << arr[i][in]<<std::endl; ++a; } } std::cout << &arr[2][0] <<std::endl; std::cout << arr[2]; std::cin.get(); return 0; }
Wenn ich nun in der Zeile arr[2] mit dem * Operator dereferenziere bekomme ich den Wert 9 (Dritte Zeile erstes Element).
Ich finde daran sieht man doch sehr gut ,dass arr im Endeffekt nur ein Pointer auf die erste Adresse des Arrays von ist,und das Arrays und Pointer sehr eng miteinander verknüpft sind.
-
VieleDimensionen schrieb:
@out
Laut dem was ich im buch gelesen habe sind Arrays und Pointer in C++ sehr eng miteinander verknüpft.
Im Buch steht geschrieben,wenn ich int arr[5] definiere und den Namen arr in einem beliebigen Ausdruck z.B. arr[1]=3; verwende wird der Name automatisch in einen Zeiger auf das erste Element des Arrays umgewandeltDas ist falsch. Das was in deinem Buch steht, ist falsch. Wie heißt dein Buch denn?
VieleDimensionen schrieb:
int main() { int a = 1; int arr[3][4]; for (int i = 0; i < 2; ++i){ for (int in = 0; i < 3; ++i) { arr[i][in] = a; ++a; } } std::cout << &arr[2][0] <<std::endl; std::cout << arr[2]; std::cin.get(); return 0; }
Es wird die selbe Adresse ausgegeben also greife ich mit arr[2] auf die erste Adresse der dritten Zeile des Arrays zu und nicht auf den Wert selbst der in diesem Array liegt.
Auch das ist falsch.
1. Mit [] greifst du immer auf den Wert des Arrays zu, und nie auf eine Adresse eines Elements. Willst du auf eine Adresse zugreifen, musst du logischerweise den Adressoperator & nehmen.<<
ist eine Funktion. Nämlichoperator<<(*/...*/)
Übergibst du ein Array an eine Funktion, findet auch array-to-pointer-decay statt. Machst du nunstd::cout << arr[2];
wirdarr[2]
an die Funktionoperator<<(*/...*/)
übergeben und du bekommst automatisch einen Zeiger auf das erste Element des Arrays. In der Funktionoperator<<(*/...*/)
wird dann einfach der Zeiger ausgegeben. Gibst du ein Zeigervariable aus, wird - wie bei jeder anderen Variable auch - der Inhalt der Variablen ausgeben. Der Inhalt einer Zeigervariablen ist die Adresse, auf die der Zeiger zeigt. Und diese Adresse ist jetzt halt die Adresse vom ersten Element des Arrays.
Wie heißt jetzt nochmal dein Buch?:D
-
Ergänzung zu oben:
Ein Array ist nie ein Zeiger auf irgendwas.
Es gibt nur bestimmte Fälle, also Ausnahmen, wo ein Array in einen Zeiger auf das erste Element konvertiert werden muss. Da findet eine Konvertierung statt. Die müsste nicht stattfinden, wenn ein Array ein Zeiger wäre. Lässt sich auch leicht beweißen, dass ein Array kein Zeiger ist.int main() { int array[5] = {1,2,3,4,5}; int nochmal_array[5] = {10,20,30,40,50}; array = nochmal_array; // Fehler int* zeiger; zeiger = nochmal_array; // Kein Fehler. }
Wäre ein Array wie ein Zeiger, gäbe es keinen Fehler...
-
Also das verwirrt mich jetzt echt.
Ich lerne mit dem C++ Primer das hier steht wörtlich so im Buch auf Seite 158:
"Zeiger und Arrays sind in C++ eng miteinander verknüpft.
Insbesondere wird der Name eines Arrays automatisch in einen Zeiger auf das erste Arrayelement umgewandelt,wenn wir ihn in einem Ausruck verwenden."
Beispiel dazu aus dem Buch:int ia[] = {0,2,4,6,8}; int *ip = ia;
Und das Buch ist ja jetzt nicht von irgendeinem Deppen verfasst und bekommt überall gute Rückmeldungen.
-
VieleDimensionen schrieb:
Also das verwirrt mich jetzt echt.
Ich lerne mit dem C++ Primer das hier steht wörtlich so im Buch auf Seite 158:
"Zeiger und Arrays sind in C++ eng miteinander verknüpft.
Insbesondere wird der Name eines Arrays automatisch in einen Zeiger auf das erste Arrayelement umgewandelt,wenn wir ihn in einem Ausruck verwenden."Das ist im Wesentlichen richtig. Es stimmt für alle Ausdrücke außer für sizeof- und Adressausdrücke.
Und das Buch ist ja jetzt nicht von irgendeinem Deppen verfasst und bekommt überall gute Rückmeldungen.
Das hat nichts zu bedeuten.
-
Ja das Buch ist gut.
Wie soll ich das jetzt erklären. Er meint nicht "immer wenn der Name des Arrays auftaucht", sondern er meint, wenn "DAS ARRAY" an sich auftaucht. Also
int ia[] = {0,2,4,6,8}; int *ip = ia; // ia => DAS ARRAY an sich.
int ia[] = {0,2,4,6,8}; int varialbe = ia[0]; // Hier ist es aber ia[N], und NICHT das Array an sich.
Verstehst du nun, worauf es hinausläuft. Also ohne Indexoperator ist das Array an sich.
-
out schrieb:
Ja das Buch ist gut.
Wie soll ich das jetzt erklären. Er meint nicht "immer wenn der Name des Arrays auftaucht", sondern er meint, wenn "DAS ARRAY" an sich auftaucht. Also
int ia[] = {0,2,4,6,8}; int *ip = ia; // ia => DAS ARRAY an sich.
int ia[] = {0,2,4,6,8}; int varialbe = ia[0]; // Hier ist es aber ia[N], und NICHT das Array an sich.
Verstehst du nun, worauf es hinausläuft. Also ohne Indexoperator ist das Array an sich.
Achso ja jetzt habe ich es auch verstanden :D.
Der Name allein ohne Index wird zum Zeiger auf das erste Element umgewandelt und der Name mit Index wird einfach direkt angesprochen.
Ich schätze mal es wird der Übersetzung des Buches ins Deutsche geschuldet sein,aber ich hatte einfach keinen Nerv so einen Wälzer komplett in Englisch zu lesen.
Nochmals vielen Dank an euch für die Hilfe.
-
out schrieb:
int ia[] = {0,2,4,6,8}; int varialbe = ia[0]; // Hier ist es aber ia[N], und NICHT das Array an sich.
Verstehst du nun, worauf es hinausläuft. Also ohne Indexoperator ist das Array an sich.
Falls du damit sagen willst, dass das Array hier nicht in einen Zeiger umgewandelt wird, liegst du falsch. Ergebnis:
Achso ja jetzt habe ich es auch verstanden :D.
Ja, toll
-
Bashar schrieb:
out schrieb:
int ia[] = {0,2,4,6,8}; int varialbe = ia[0]; // Hier ist es aber ia[N], und NICHT das Array an sich.
Verstehst du nun, worauf es hinausläuft. Also ohne Indexoperator ist das Array an sich.
Falls du damit sagen willst, dass das Array hier nicht in einen Zeiger umgewandelt wird, liegst du falsch. Ergebnis:
Achso ja jetzt habe ich es auch verstanden :D.
Ja, toll
Oh nein bitte nicht
.
Und wer hat jetzt Recht?
-
Bashar schrieb:
out schrieb:
int ia[] = {0,2,4,6,8}; int varialbe = ia[0]; // Hier ist es aber ia[N], und NICHT das Array an sich.
Verstehst du nun, worauf es hinausläuft. Also ohne Indexoperator ist das Array an sich.
Falls du damit sagen willst, dass das Array hier nicht in einen Zeiger umgewandelt wird, liegst du falsch.
Das hör ich jetzt zum ersten Mal. Kann das jemand bestätigen
?
-
Du könntest in einem C++-Buch deines Vertrauens oder im Standard nachlesen, wie der []-Operator definiert ist.
-
So ich habe nochmal nachgeforscht auf der MSDN Seite wird es auch so erklärt:
"Usually, the value represented by postfix-expression is a pointer value, such as an array identifier, and expression is an integral value (including enumerated types). However, all that is required syntactically is that one of the expressions be of pointer type and the other be of integral type. Thus the integral value could be in the postfix-expression position and the pointer value could be in the brackets in the expression or subscript position. Consider the following code fragment:"
int nArray[5] = { 0, 1, 2, 3, 4 }; cout << nArray[2] << endl; // prints "2" cout << 2[nArray] << endl; // prints "2"
Und hier die fortsetzung:
"In the preceding example, the expression nArray[2] is identical to 2[nArray]. The reason is that the result of a subscript expression e1[ e2 ] is given by:"*( (e2) + (e1) )
Das Ergebniss wird also mit dem vorangestellten * dereferenziert was ja nochmal deutlich macht,dass es sich hier im einen Pointer handelt .