Ich versuche, das Programm unten zu verstehen, aber es ist mir nicht klar.
#include<stdio.h>
int main()
{
int a[]={1,2,3,4,5,6,9};
printf("sizeof array is %d\n",sizeof(a));
printf("size of array using logic is %d\n",((&a)[1]-a));
printf("value of (&a)[1] is %p \n",(&a)[1]);
printf("value of a is %p \n",a);
printf("address of a[0] is %p\n",&a[0]);
printf("address of a[1] is %p\n",&a[1]);
printf("address of a[2] is %p\n",&a[2]);
printf("address of a[3] is %p\n",&a[3]);
printf("address of a[4] is %p\n",&a[4]);
printf("address of a[5] is %p\n",&a[5]);
printf("address of a[6] is %p\n",&a[6]);
}
Die obige Codeausgabe ist:
sizeof array is 28
size of array using logic is 7
value of (&a)[1] is 0x7ffc4888e78c
value of a is 0x7ffc4888e770
address of a[0] is 0x7ffc4888e770
address of a[1] is 0x7ffc4888e774
address of a[2] is 0x7ffc4888e778
address of a[3] is 0x7ffc4888e77c
address of a[4] is 0x7ffc4888e780
address of a[5] is 0x7ffc4888e784
address of a[6] is 0x7ffc4888e788
Warum ist mir nicht klar ((&a)[1]-a)) bei der zweiten Druckanweisung wird 7 zurückgegeben; es sollte sein 0x7ffc4888e78c - 0x7ffc4888e770 welches ist 0x1c dh 28 Gesamtgröße des Arrays.
Als Referenz habe ich auch versucht zu drucken (&a)[1] und ein Wert, den Sie im Code sehen können. Ich habe auch versucht zu debuggen.
(&a)[1]-a ist Zeigerdifferenz.
– Hacken
2. Juni 2016 um 5:07 Uhr
Aktivieren Sie Compiler-Warnungen und beachten Sie, dass Sie haben %zu zum size_t.
– sjsam
2. Juni 2016 um 5:22 Uhr
@hackks warum ist der Zeigerunterschied 7 nicht etwas anderes?
– Mohan
2. Juni 2016 um 5:22 Uhr
@Mohan, weil keine der Array-Elemente 7 sind
– Cherubim
2. Juni 2016 um 5:24 Uhr
@harisch; Die Zeigerdifferenz entspricht als Ergebnis dem ganzzahligen Ausdruck, nicht einer Adresse.
– Hacken
2. Juni 2016 um 7:48 Uhr
Fuhrmann
Wenn Sie werfen (&a)[1] und a zu long vor der Berechnung, dann erhalten Sie Ihr erwartetes Ergebnis. Wie Hacks kommentierte, berechnen Sie gerade die Zeigerdifferenz.
// These two sizes will be the same
printf("sizeof array is %ld\n",sizeof(a));
printf("size of array using logic is %ld\n",((long)(&a)[1]-(long)a));
Mathematik erklären
Was in diesem Fall passiert, ist &a gilt als Typ int(*)[7].
Dann verweisen Sie (&a)[1]was übersetzt heißt *((&a)+1). Auf Englisch bedeutet dies „gib mir den Punkt in Speicher 1 nach dem Beginn von a.” Wie &a zufällig Typ sein int(*)[7]dieser Punkt befindet sich am Ende des Arrays.
Wenn Sie subtrahieren adem Zeiger auf den Anfang des Arrays, führen Sie Zeigerarithmetik durch und nehmen eine Basis in der Größe von an int (Weil a ist ein int Reihe). Also der Ausdruck ((&a)[1]-a) zählt wie viele int sind dazwischen (&a)[1] und a.
Eine Übersicht zur Zeigerarithmetik findet sich hier.
Ja, danke, aber ohne Typumwandlung bekomme ich 7, was mir immer noch nicht klar ist. Alle sagen, dass es dasselbe ist wie sizeof (a) / sozeof (a[0]).Aber zu sagen, dass es ähnlich ist, ist in Ordnung, aber während des Debuggens, wie kann ich diesen Unterschied klar verstehen.
– Harisch
2. Juni 2016 um 5:46 Uhr
Dies ist ein Teil der Zeigermathematik. Sie können mehr darüber lesen hier. Ich habe die Antwort mit einer ausführlicheren Beschreibung dessen aktualisiert, was passiert.
– Carter
2. Juni 2016 um 5:58 Uhr
@2501 Warum nicht &a Typ int*[7]? Mein Compiler sagt mir, dass das richtig ist.
– Carter
2. Juni 2016 um 6:20 Uhr
@ 2501 Danke, ich habe meine Notation durcheinander gebracht. Ich meinte int(*)[7]. Antwort entsprechend aktualisiert.
– Carter
2. Juni 2016 um 6:39 Uhr
nicht zu werfen longverwenden ptrdiff_t und mit drucken %td oder off_t und mit drucken %jd
– phuklv
2. Juni 2016 um 6:42 Uhr
Zeiger sind also keine ganzen Zahlen. Sicher, Sie können sie in Ganzzahlen umwandeln, indem Sie sie in einen Ganzzahltyp umwandeln, oder ihnen Ganzzahlen hinzufügen, um sie herumzuschieben. Aber sie sind keine ganzen Zahlen.
Zeiger sind wie mathematische Vektoren über den ganzen Zahlen, wenn Sie sich mit linearer Algebra beschäftigt haben.
p1-p2 ist der Abstand zwischen p1 und p2die zu addierende Ganzzahl p2 erreichen p1.
Wenn Sie einem Zeiger eine ganze Zahl hinzufügen, müssen Sie auf den Typ des Zeigers achten. Wenn der Zeiger auf ein Objekt der Größe 4 zeigt, erhöht sich jedes Mal, wenn Sie 1 zu einem Zeiger addieren, seine numerische Adresse um 4, nicht um 1.
Das Gleiche gilt, wenn Sie zwei Zeiger subtrahieren.
Der Schlüsselteil hier ist, dass der numerische Wert der Adresse im Speicher wichtig ist, aber der Typ ist genauso wichtig zu verstehen, was passiert.
Die zweite seltsame Sache, die hier vor sich geht, sind diese Arrays Verfall im Handumdrehen in Zeiger auf ihr erstes Element umwandeln. Sie sind es jedoch nicht Zeiger auf ihr erstes Element, sie wandeln sich einfach sehr leicht in sie um.
Also, wenn wir das tun:
(&a)[1]
Wir nehmen die Adresse von a. Die Adresse von a ist ein Zeiger vom Typ int(*)[7]. Es ist ein Zeiger zu einem Array, kein Zeiger auf das erste Element des Arrays. Der Unterschied liegt in der Art des Zeigers. Und diese 7 ist wichtig.
Wir verwenden dann []auf dem Zeiger. Wenn Sie einen Zeiger oder ein Array haben p und einen Wert v, p[v] definiert ist *(p+v). Dies führt zu Humor, wenn Sie dies tun v[p]aber das ist nicht wichtig.
Lassen pa vertreten (&a). Dann pa[1] wird sein *(pa + 1).
Jetzt, pa ist ein Zeiger auf ein Array (kein Zeiger auf das erste Element des Arrays). Also addiert +1 die volle Größe des Arrays (sizeof(int)*7) zum numerischen Wert.
So pa+1 ist ein Zeiger auf eins nach dem Ende von aund ist vom Typ Pointer-to-Array.
Wir dereferenzieren dann und erhalten das nicht vorhandene Array der Größe 7 direkt nach dem Ende des Arrays a.
Dann subtrahieren wir a.
(&a)[1]-a
Hier setzt der Zeigerzerfall ein. Es gibt keinen - Operation auf Arrays, aber es gibt eine - Betrieb auf Zeigern. Also die C-Sprache hilfreich zerfällt jedes dieser Arrays in Zeiger auf ihr erstes Element.
Der Zeiger auf das erste Element von a ist &a[0].
Der Zeiger auf das erste Element des Arrays der Größe 7 unmittelbar nach dem Ende von a ist … &a[7].
Beide Zeiger sind vom Typ int*. Wenn Sie zwei subtrahieren int*s erhalten Sie ihren numerischen Zeigerwert geteilt durch sizeof(int). In diesem Fall ist das einfach – 7.
Dies könnte einfacher sein, wenn wir uns das ansehen:
(&a)[1]-(&a)[0]
oder
*(&a+1)-*(&a+0)
&a ist ein Zeiger auf das Array a vom Typ “Zeiger auf Array der Größe 7”. Wir addieren 1 dazu und erhalten danach in einem Fall den Zeiger auf das Array und im anderen Fall Null.
Wir gehen dann zurück zu Arrays und subtrahieren. Die Subtraktion löst Zerfall auf den Zeiger auf das erste Element aus, sodass wir einen Zeiger auf das Element direkt nach dem Ende von a und einen Zeiger auf das erste Element von a erhalten.
&a[7]-&a[0]
welches ist
&*(a+7)-&*(a+0)
Jetzt &* macht nichts mit Dingen, die bereits Zeiger sind (was sie zu diesem Zeitpunkt sind), also:
(a+7)-(a+0)
Dann stellt sich die Frage, wie viel Sie hinzufügen müssen a+0 erreichen a+7. Die Antwort ist wenig überraschend 7:
(a+7) = (a+0)+7
und das wird angezeigt.
Danke für die klare Erklärung. Ich habe es herausgefunden, indem ich objdump auf diesen Code und auch mit Typumwandlungscode überprüft habe.
– Harisch
3. Juni 2016 um 5:06 Uhr
hackt
(&a)[1] ist die Adresse des Speicherplatzes hinter dem Array adh 0x7ffc4888e788. (&a)[1] ist vom Typ int *. Nach der Konvertierung a wird vom Typ sein int *. Es ist äquivalent zu (&a)[0].
Norm sagt dazu:
C11-§6.5.6/9:
Wenn zwei Zeiger subtrahiert werden, zeigen beide auf Elemente desselben Array-Objekts oder einen nach dem letzten Element des Array-Objekts; das Ergebnis ist die Differenz der Indizes der beiden Array-Elemente.
Der Unterschied (&a)[1]-a gibt die Anzahl der Elemente im Array an a. Beachten Sie, dass ain diesem Ausdruck ist die Adresse des Array-Elements a[0]nach dem Zerfall, und diese Adresse entspricht der Adresse des Arrays aobwohl &a und a[0] anderen Typ haben.
Sie können sich diesen Unterschied vorstellen als (&a)[1]-(&a)[0] oder &a[7] - &a[0].
sizeof(a) gibt die dem Array zugewiesene Speichergröße an a. sizeof(a)/sizeof(a[0]) gibt die Anzahl der Elemente des Arrays an a.
Gibt es eine theoretische Erklärung dafür, warum (&a)[1] gibt Adresse des Speicherplatzes hinter dem Array und (&a)[1]-a gibt die Anzahl der Elemente im Array a und der Rückgabewert ändert sich beim Casting long wie @Carter erwähnt?
– Cherubim
2. Juni 2016 um 5:44 Uhr
Wenn Sie eine kleine Anmerkung zum Unterschied zwischen (&a) machen könnten[x] und ein[x]das wird für das zukünftige Publikum hilfreich sein 🙂
– sjsam
2. Juni 2016 um 5:49 Uhr
@CherubimAnand Ja, das gibt es! Ich habe meine Antwort mit einer ausführlicheren Erklärung aktualisiert, aber es läuft im Grunde auf Zeigerarithmetik hinaus. Sie können mehr darüber lesen hier.
– Carter
2. Juni 2016 um 6:05 Uhr
@CherubimAnand; Nach dem Casting ist es kein Zeigerunterschied mehr, sondern ein ganzzahliger Unterschied. Ganzzahlige Differenz von 0 - 4 wird geben 4 während Zeiger Unterschied geben wird 1 (vorausgesetzt long Größe 4).
– Hacken
2. Juni 2016 um 6:15 Uhr
(&a)[0] und &a sind nicht dasselbe. (&a)[1]-&a wäre ein Syntaxfehler, während “(&a)[1]-(&a)[0]` ist dasselbe wie (&a)[1]-a was dasselbe ist wie (&a)[1]-&(a[0]). Typen sind wichtig.
– Yakk – Adam Nevraumont
2. Juni 2016 um 15:48 Uhr
Anton Oschtschepko
Sie betreibt aber int* Zeiger. Alle arithmetischen Operationen darauf verwenden 4 bytes (sizeof(int) um genau zu sein) als Einheit. Differenz zwischen zwei Zeigern, ausgedrückt in dieser Einheit. ((&a)[1]-a)) ist gleich wie sizeof(a)/sizeof(a[0]). Um die Array-Größe in Bytes zu berechnen, müssen Sie den Zeiger auf einen ganzzahligen Wert umwandeln, unsigned int:
printf("size of array using logic is %d\n",((int)((&a)[1])-(int)a));
Grzegorz Szpetkowski
Wenn Sie die Anzahl der Bytes erhalten möchten, ohne zu verwenden sizeof Betreiber, dann anstatt zu werfen long data type*, ich denke, dass der idiomatischere und sicherere Weg darin besteht, beide Zeiger zu werfen char *:
printf("Size of array using pointer arithmethic is %td.\n", (char*)(&a)[1] - (char*)a);
Ergebnis:
Die Größe des Arrays mit Zeigerarithmetik beträgt 28.
Beachten Sie, dass %td Formatbezeichner ist für Datentyp geeignet ptrdiff_t (definiert in <stddef.h>), so wird die Zeigerdifferenz dargestellt.
*) Es gibt dedizierte Datentypen intptr_t und uintptr_t um Objektzeiger als ganze Zahlen darzustellen, wenn Sie das wirklich brauchen.
Harisch
Erster Dank an alle und besonderer Dank an Yakk, der mir eine so großartige Analyse der einfachen Pointer-Arthamatik gegeben hat. Ich habe endlich herausgefunden, warum es passiert, wie @Yakk ausführlich erklärte, was mich in hohem Maße klärte, aber immer noch einige Zweifel daran hatte. Also fing ich an, den Code zu ändern und versuchte, die Zeigerartematik zu überprüfen. Eine kurze Antwort ist, wenn &a[0] verwendet wird, bezieht es sich auf das erste Element in der Array-Adresse. Wenn a oder &a verwendet werden, beziehen sie sich auf die Basisadresse des vollständigen Arrays der Größe 7. Um das klarzustellen, haben wir (&a) verwendet.[0] die auf die Basisadresse des Arrays der Größe 7 zeigen, wenn sie auf 1 inkrementiert werden, geht es um eine Stelle nach dem Ende des Arrays a. Wie von –Yakk wie folgt erklärt: Dies könnte einfacher sein, wenn wir uns das ansehen:
(&a)[1]-(&a)[0]
oder
(&a+1)-(&a+0)
&a ist ein Zeiger auf das Array a vom Typ “Zeiger auf Array der Größe 7”. Wir addieren 1 dazu und erhalten danach in einem Fall den Zeiger auf das Array und im anderen Fall Null.
Wir gehen dann zurück zu Arrays und subtrahieren. Die Subtraktion löst Zerfall auf den Zeiger auf das erste Element aus, sodass wir einen Zeiger auf das Element direkt nach dem Ende von a und einen Zeiger auf das erste Element von a erhalten.
&a[7]-&a[0]
welches ist
&(a+7)-&(a+0)
Jetzt macht &* nichts mit Dingen, die bereits Zeiger sind (was sie an diesem Punkt sind), also:
(a+7)-(a+0)
Dann stellt sich die Frage, wie viel Sie zu a+0 hinzufügen müssen, um a+7 zu erreichen. Die Antwort ist wenig überraschend 7:
(a+7) = (a+0)+7
und das wird angezeigt.
12985300cookie-checkArray-Größe ohne sizeof-Operatoryes
(&a)[1]-a
ist Zeigerdifferenz.– Hacken
2. Juni 2016 um 5:07 Uhr
Aktivieren Sie Compiler-Warnungen und beachten Sie, dass Sie haben
%zu
zumsize_t
.– sjsam
2. Juni 2016 um 5:22 Uhr
@hackks warum ist der Zeigerunterschied 7 nicht etwas anderes?
– Mohan
2. Juni 2016 um 5:22 Uhr
@Mohan, weil keine der Array-Elemente 7 sind
– Cherubim
2. Juni 2016 um 5:24 Uhr
@harisch; Die Zeigerdifferenz entspricht als Ergebnis dem ganzzahligen Ausdruck, nicht einer Adresse.
– Hacken
2. Juni 2016 um 7:48 Uhr