Verhalten von 2D-Arrays

Lesezeit: 5 Minuten

Benutzer-Avatar
Kevin Richards

Ich habe ein 2D-Array erstellt und versucht, bestimmte Werte wie unten gezeigt zu drucken:

int a[2][2] = { {1, 2}, 
                {3, 4}};

printf("%d %d\n", *(a+1)[0], ((int *)a+1)[0]);

Die Ausgabe ist:

3 2

ich verstehe warum 3 ist die erste Ausgabe (a+1 zeigt auf die zweite Zeile, und wir drucken sie 0th Element.

Meine Frage bezieht sich auf die zweite Ausgabe, dh 2. Meine Vermutung liegt an der Typisierung a wie int *wird das 2D-Array wie ein 1D-Array behandelt und somit a+1 fungiert als Zeiger auf die 2nd Element, und so erhalten wir die Ausgabe als 2.

Sind meine Annahmen richtig oder steckt dahinter eine andere Logik?
Auch ursprünglich, was ist die Art von a wenn es als Zeiger behandelt wird int (*)[2] oder int **?

  • Die Besetzung hat eine höhere Angemessenheit, sodass Sie ein undefiniertes Verhalten aufrufen, wenn Sie versuchen, zu dereferenzieren a+1.

    – Benutzer657267

    16. Juli 2014 um 22:35 Uhr

  • @ user657267 es gibt kein UB

    – MM

    16. Juli 2014 um 22:58 Uhr

  • Hoppla, Arrays sind natürlich flach.

    – Benutzer657267

    16. Juli 2014 um 23:30 Uhr

  • Notiz: *(a+1)[3] ist nicht dasselbe wie (*(a+1))[3] (es sei denn, die zweite Zahl ist Null, was in Ihrem Code steht)

    – Benutzer253751

    17. Juli 2014 um 3:47 Uhr


  • Beachten Sie auch, dass, wenn das “Array” tatsächlich a ist int** (wo die Zeilen des Arrays waren mallocmanuell bearbeitet), obwohl es wie eine aufgerufen werden kann array[x][y]es in ein 1D-Array umzuwandeln und darauf zuzugreifen, wird im besten Fall den Wert von a zurückgeben Zeiger (also Müll aus der Sicht des Anrufers)

    – Marco13

    17. Juli 2014 um 9:35 Uhr

Benutzer-Avatar
Vlad aus Moskau

Als Sie Ausdruck geschrieben haben

(int *)a

dann kann das ursprüngliche Array logischerweise auf folgende Weise als eindimensionales Array betrachtet werden

int a[4] = { 1, 2, 3, 4 };

Also Ausdruck a zeigt auf das erste Element gleich 1 dieses imaginären Arrays. Ausdruck ( a + 1 ) zeigt auf das zweite Element des imaginären Arrays gleich 2 und Ausdruck ( a + 1 )[0] gibt den Verweis auf dieses Element zurück, das heißt, Sie erhalten 2.

  • Welche Beweise haben Sie, dass dies von der Norm vorgeschrieben wird?

    – Yakk – Adam Nevraumont

    17. Juli 2014 um 2:16 Uhr

Benutzer-Avatar
hackt

Sind meine Annahmen richtig oder steckt dahinter eine andere Logik?

Ja.

*(a+1)[0] ist äquivalent zu a[1][0].
((int *)a+1)[0] ist äquivalent zu a[0][1].

Erläuterung:

a zerfällt zum Zeiger auf das erste Element des 2D-Arrays, dh auf die erste Zeile. *a dereferenziert diese Zeile, die ein Array von 2 ist int. Deswegen *a kann als Array-Name der ersten Zeile behandelt werden, der weiter in einen Zeiger auf sein erstes Element zerfällt, dh 1. *a + 1 gibt den Zeiger auf das zweite Element. Dereferenzierung *a + 1 wird geben 1. So:

((int *)a+1)[0] == *( ((int *)a+1 )+ 0) 
                == *( ((int *)a + 0) + 1) 
                == a[0][1]   

Beachten Sie, dass a, *a, &a, &a[0] und &a[0][0] alle haben den gleichen Adresswert, obwohl sie unterschiedlichen Typs sind. Nach dem Verfall, a ist vom Typ int (*)[2]. Gießen Sie es zu int * macht nur den Adresswert zu tippen int * und die Arithmetik (int *)a+1 gibt die Adresse des zweiten Elements an.

Was ist ursprünglich der Typ von a, wenn es als Zeiger behandelt wird? (int (*)[2] oder int **?

Es wird typisiert Zeiger auf Array von 2 intdh int (*)[2]

  • Diese Antwort enthält keine Erklärung dafür, warum dies der Fall ist. Die Gleichwertigkeit geht aus den ausgegebenen Zahlen hervor, bitte begründen Sie diese Gleichwertigkeit. Es beantwortet auch nicht die Frage am Ende des Beitrags.

    – Mike Precup

    16. Juli 2014 um 22:40 Uhr

  • In Übereinstimmung mit den Website-Regeln stimme ich basierend auf dem aktuellen Status eines Beitrags ab, nicht wie er möglicherweise sein könnte. Daher habe ich meine Stimme geändert, jetzt da der Beitrag die Frage beantwortet.

    – Mike Precup

    16. Juli 2014 um 22:45 Uhr

  • @hackks Es ist, als würde man einem Kunden eine Pizza ungekocht und ohne Belag servieren, „Bestellen!“ schreien und dann sauer werden, wenn er darauf hinweist, dass die servierte Pizza einfach nicht angemessen ist. Abgesehen davon, warum geben Sie überhaupt Antworten mit Versionen? 3 auf der Platte und diese schließen die kleineren aus …

    – Utkan Geser

    16. Juli 2014 um 23:00 Uhr

  • @ThoAppelsin – Hast du nie eine deiner Antworten verbessert? Meine Güte. Schauen Sie sich einige der besten Antworten auf SO an, die meisten von ihnen haben mehrere Änderungen. Dieses hier zum Beispiel, 15 Bearbeitungen Es ist nichts falsch an einer Bearbeitung, die die Antwort verbessert.

    – ryker

    17. Juli 2014 um 0:17 Uhr


  • @ryyker Ich glaube, was ich gesagt habe, darf nicht aus dem Zusammenhang gerissen werden. hackt sagte gleich bei seinem ersten Kommentar etwas über Geduld; was meiner Meinung nach zu Recht interpretiert wurde “Beurteilen Sie meine Antwort nicht so schnell, sie war damals noch nicht vollständig, ich habe sie noch vorbereitet.”. Natürlich kann man ihre Antwort verbessern, ich auch; Das Problem hier ist, dass er anscheinend die erste Version mit dem Plan gepostet hat, so schnell wie möglich eine Bearbeitung bereitzustellen, was ich nie tue. Widerlegen Sie mich, wenn Sie möchten, es ist unangebracht, eine Antwort voreilig zu posten, wenn Sie wissen, dass sie noch nicht vollständig ist.

    – Utkan Geser

    17. Juli 2014 um 0:36 Uhr

Ein 2D-Array ist im Wesentlichen ein eindimensionales Array mit einigen zusätzlichen Compiler-Kenntnissen.

Wenn Sie werfen a zu int*entfernen Sie dieses Wissen und es wird wie ein normales eindimensionales Array behandelt (was in Ihrem Fall im Speicher so aussieht 1 2 3 4).

Benutzer-Avatar
Utkan Geser

Das Wichtigste, was hier zu erkennen ist, ist, dass die a Dort steht der Wert der Adresse, an der sich die erste Zeile befindet. Da das gesamte Array an derselben Stelle beginnt, hat das gesamte Array auch denselben Adresswert; Gleiches gilt für das allererste Element.

Im C Bedingungen:

&a == &a[0];
&a == &a[0][0];
&a[0] == &a[0][0];
// all of these hold true, evaluate into 1
// cast them if you want, looks ugly, but whatever...
&a == (int (*)[2][2]) &a[0];
&a == (int (*)[2][2]) &a[0][0];
&a[0] == (int (*)[2]) &a[0][0];

Aus diesem Grund, wenn Sie die werfen a zu int *wird es einfach 1-zu-1-äquivalent zu &a[0][0] sowohl über den Typ als auch über den Wert. Wenn Sie diese Operationen auf anwenden würden &a[0][0]:

(&a[0][0] + 1)[0];
(a[0] + 1)[0];
*(a[0] + 1);
a[0][1];

Was die Art angeht a wenn es als Zeiger behandelt wird, obwohl ich mir nicht sicher bin, sollte es sein int (*)[2].

1054940cookie-checkVerhalten von 2D-Arrays

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy