Wie kommt es, dass die Adresse eines Arrays gleich seinem Wert in C ist?

Lesezeit: 9 Minuten

Benutzeravatar von Alexandre
Alexandre

Im folgenden Codebit unterscheiden sich Zeigerwerte und Zeigeradressen wie erwartet.

Aber Array-Werte und Adressen nicht!

Wie kann das sein?

Ausgabe

my_array = 0022FF00
&my_array = 0022FF00
pointer_to_array = 0022FF00
&pointer_to_array = 0022FEFC
#include <stdio.h>

int main()
{
  char my_array[100] = "some cool string";
  printf("my_array = %p\n", my_array);
  printf("&my_array = %p\n", &my_array);

  char *pointer_to_array = my_array;
  printf("pointer_to_array = %p\n", pointer_to_array);
  printf("&pointer_to_array = %p\n", &pointer_to_array);

  printf("Press ENTER to continue...\n");
  getchar();
  return 0;
}

  • Aus der comp.lang.c FAQ: – [So what is meant by the “equivalence of pointers and arrays” in C? ](c-faq.com/aryptr/aryptrequiv.html) – [Since array references decay into pointers, if arr is an array, what’s the difference between arr and &arr? ](c-faq.com/aryptr/aryvsadr.html) Oder lesen Sie das Ganze Arrays und Zeiger Sektion.

    – jamesdlin

    27. März 2010 um 9:18 Uhr

  • Ich hatte vor zwei Jahren hier eine Antwort mit Diagramm zu dieser Frage hinzugefügt sizeof(&array) Rückkehr?

    – Grijesh Chauhan

    8. Mai 2015 um 16:39 Uhr


  • Beantwortet das deine Frage? Was ist Array-to-Pointer-Zerfall?

    – Andreas Wenzel

    11. Januar um 6:46 Uhr

Benutzeravatar von Jerry Coffin
Jerry Sarg

Der Name eines Arrays ergibt normalerweise die Adresse des ersten Elements des Arrays, also array und &array denselben Wert haben (aber unterschiedliche Typen, also array+1 und &array+1 Wille nicht gleich sein, wenn das Array mehr als 1 Element lang ist).

Davon gibt es zwei Ausnahmen: Wenn der Array-Name ein Operand von ist sizeof oder unär & (address-of) bezieht sich der Name auf das Array-Objekt selbst. Daher sizeof array gibt Ihnen die Größe des gesamten Arrays in Bytes an, nicht die Größe eines Zeigers.

Für ein Array definiert als T array[size]es wird Typ haben T *. Wenn/falls Sie es erhöhen, gelangen Sie zum nächsten Element im Array.

&array wertet dieselbe Adresse aus, erstellt jedoch bei derselben Definition einen Zeiger des Typs T(*)[size] — dh es ist ein Zeiger auf ein Array, nicht auf ein einzelnes Element. Wenn Sie diesen Zeiger erhöhen, wird die Größe des gesamten Arrays hinzugefügt, nicht die Größe eines einzelnen Elements. Zum Beispiel mit Code wie diesem:

char array[16];
printf("%p\t%p", (void*)&array, (void*)(&array+1));

Wir können davon ausgehen, dass der zweite Zeiger um 16 größer ist als der erste (weil es sich um ein Array mit 16 Zeichen handelt). Da %p normalerweise Zeiger in Hexadezimal umwandelt, könnte es etwa so aussehen:

0x12341000    0x12341010

  • @ Alexander: &array ist ein Zeiger auf das erste Element des Arrays, wobei as array bezieht sich auf das gesamte Array. Der grundsätzliche Unterschied lässt sich auch im Vergleich feststellen sizeof(array)zu sizeof(&array). Beachten Sie jedoch, dass, wenn Sie bestehen array nur als Argument für eine Funktion &array ist tatsächlich bestanden. Sie können ein Array nicht als Wert übergeben, es sei denn, es ist in a gekapselt struct.

    – Clifford

    27. März 2010 um 7:52 Uhr

  • @Clifford: Wenn Sie ein Array an eine Funktion übergeben, zerfällt es so effektiv zu einem Zeiger auf sein erstes Element &array[0] bestanden ist, nicht &array was ein Zeiger auf das Array wäre. Es mag ein Nitpick sein, aber ich denke, es ist wichtig, das klarzustellen; Compiler warnen, wenn die Funktion einen Prototyp hat, der mit dem Typ des übergebenen Zeigers übereinstimmt.

    – CB Bailey

    27. März 2010 um 9:53 Uhr

  • @Jerry Coffin Zum Beispiel int *p = &a, wenn ich die Speicheradresse des int-Zeigers p haben möchte, kann ich &p tun. Da &array in die Adresse des gesamten Arrays konvertiert (das bei der Adresse des ersten Elements beginnt). Wie finde ich dann die Speicheradresse des Array-Zeigers (der die Adresse des ersten Elements im Array speichert)? Es muss irgendwo im Speicher sein, oder?

    – John Lee

    12. September 2012 um 8:44 Uhr


  • @JohnLee: Nein, es muss nirgendwo im Speicher ein Zeiger auf das Array vorhanden sein. Wenn Sie einen Zeiger erstellen, können Sie seine Adresse nehmen: int *p = array; int **pp = &p;.

    – Jerry Sarg

    12. September 2012 um 14:06 Uhr

  • @Clifford der erste Kommentar ist falsch, warum behältst du ihn trotzdem? Ich denke, es könnte zu Missverständnissen für diejenigen führen, die die folgende Antwort von (@Charles) nicht lesen.

    – Rick

    9. April 2018 um 2:24 Uhr


Das liegt daran, dass die Array-Name (my_array) unterscheidet sich von einem Zeiger auf ein Array. Es ist ein Alias ​​für die Adresse eines Arrays, und seine Adresse ist als die Adresse des Arrays selbst definiert.

Der Zeiger ist jedoch eine normale C-Variable auf dem Stack. So können Sie seine Adresse nehmen und einen anderen Wert als die darin enthaltene Adresse erhalten.

Ich habe über dieses Thema geschrieben hier – Bitte schau es dir an.

  • Sollte &my_array keine ungültige Operation sein, da der Wert von my_array nicht auf dem Stapel ist, sondern nur my_array[0…length] sind? Dann würde alles Sinn machen…

    – Alexandre

    27. März 2010 um 6:22 Uhr

  • @Alexandre: Ich bin mir nicht sicher, warum es eigentlich erlaubt ist.

    – Eli Bendersky

    27. März 2010 um 6:46 Uhr

  • Sie können die Adresse jeder Variablen nehmen (falls nicht markiert register) unabhängig von ihrer Speicherdauer: statisch, dynamisch oder automatisch.

    – CB Bailey

    27. März 2010 um 10:00 Uhr

  • my_array selbst ist auf dem Stack, weil my_array ist das gesamte Array.

    – Café

    27. März 2010 um 12:42 Uhr

  • my_arraywenn nicht das Thema der & oder sizeof Operatoren, wird zu einem Zeiger auf sein erstes Element ausgewertet (d. h. &my_array[0]) – aber my_array selbst ist nicht dieser Zeiger (my_array ist immer noch das Array). Dieser Zeiger ist nur ein kurzlebiger Rvalue (z. B. gegeben int a;es ist genau wie a + 1) – zumindest konzeptionell wird “nach Bedarf kalkuliert”. Der wahre “Wert” von my_array ist der Inhalt des gesamten Arrays – es ist nur so, dass das Festhalten dieses Werts in C wie der Versuch ist, Nebel in einem Glas einzufangen.

    – Café

    28. März 2010 um 21:18 Uhr

Benutzeravatar von CB Bailey
CB Bailey

Wenn Sie in C den Namen eines Arrays in einem Ausdruck verwenden (einschließlich der Übergabe an eine Funktion), es sei denn, es handelt sich um den Operanden der Adresse von (&) Betreiber oder der sizeof Betreiber, es zerfällt zu einem Zeiger auf sein erstes Element.

Das heißt, in den meisten Zusammenhängen array ist äquivalent zu &array[0] in Art und Wert.

In deinem Beispiel my_array Typ hat char[100] die zu a zerfällt char* wenn Sie es an printf übergeben.

&my_array Typ hat char (*)[100] (Zeiger auf Array von 100 char). Da es sich um den Operanden to handelt &dies ist einer der Fälle, die my_array zerfällt nicht sofort in einen Zeiger auf sein erstes Element.

Der Zeiger auf das Array hat denselben Adresswert wie ein Zeiger auf das erste Element des Arrays, da ein Array-Objekt nur eine zusammenhängende Folge seiner Elemente ist, aber ein Zeiger auf ein Array hat einen anderen Typ als ein Zeiger auf ein Element von dieses Array. Dies ist wichtig, wenn Sie Zeigerarithmetik mit den beiden Zeigertypen durchführen.

pointer_to_array Typ hat char * – initialisiert, um auf das erste Element des Arrays zu zeigen, da das was ist my_array zerfällt in den Initialisierungsausdruck – and &pointer_to_array Typ hat char ** (Zeiger auf einen Zeiger auf a char).

Von diesen: my_array (nach Zerfall auf char*), &my_array und pointer_to_array alle zeigen entweder direkt auf das Array oder das erste Element des Arrays und haben daher denselben Adresswert.

Der Grund warum my_array und &my_array zur gleichen Adresse führen, lässt sich leicht verstehen, wenn man sich das Speicherlayout eines Arrays ansieht.

Angenommen, Sie haben ein Array mit 10 Zeichen (anstelle der 100 in Ihrem Code).

char my_array[10];

Speicher für my_array sieht ungefähr so ​​aus:

+---+---+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+---+---+
^
|
Address of my_array.

In C/C++ zerfällt ein Array zum Zeiger auf das erste Element in einem Ausdruck wie z

printf("my_array = %p\n", my_array);

Wenn Sie untersuchen, wo sich das erste Element des Arrays befindet, werden Sie feststellen, dass seine Adresse mit der Adresse des Arrays identisch ist:

my_array[0]
|
v
+---+---+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+---+---+
^
|
Address of my_array[0].

In der Programmiersprache B, dem unmittelbaren Vorgänger von C, waren Zeiger und ganze Zahlen frei austauschbar. Das System würde sich verhalten, als wäre der gesamte Speicher ein riesiges Array. Jedem Variablennamen war entweder eine globale oder eine Stack-relative Adresse zugeordnet. Für jeden Variablennamen musste der Compiler nur nachverfolgen, ob es sich um eine globale oder eine lokale Variable handelte, und ihre Adresse relativ zur ersten globalen oder lokalen Variable.

Angesichts einer globalen Erklärung wie i; [there was no need to specify a type, since everything was an integer/pointer] würde vom Compiler wie folgt verarbeitet werden: address_of_i = next_global++; memory[address_of_i] = 0; und eine Aussage wie i++ würde verarbeitet als: memory[address_of_i] = memory[address_of_i]+1;.

Eine Erklärung wie arr[10]; würde wie verarbeitet werden address_of_arr = next_global; memory[next_global] = next_global; next_global += 10;. Beachten Sie, dass sobald diese Erklärung bearbeitet wurde, der Compiler konnte sofort vergessen arr ein Array sein. Eine Aussage wie arr[i]=6; würde wie verarbeitet werden memory[memory[address_of_a] + memory[address_of_i]] = 6;. Dem Compiler wäre es egal, ob arr repräsentiert ein Array und i eine ganze Zahl oder umgekehrt. Tatsächlich wäre es egal, ob sie beide Arrays oder beide Integer wären; es würde den Code problemlos wie beschrieben generieren, ohne Rücksicht darauf, ob das resultierende Verhalten wahrscheinlich nützlich wäre.

Eines der Ziele der Programmiersprache C war es, weitgehend kompatibel mit B zu sein. In B der Name eines Arrays [called a “vector” in the terminology of B] identifizierte eine Variable, die einen Zeiger enthielt, der ursprünglich zugewiesen wurde, um auf das erste Element einer Zuweisung der angegebenen Größe zu zeigen. Wenn dieser Name also in der Argumentliste für eine Funktion auftauchte, würde die Funktion einen Zeiger auf den Vektor erhalten. Obwohl C “echte” Array-Typen hinzufügte, deren Name fest mit der Adresse der Zuordnung verknüpft war und nicht mit einer Zeigervariablen, die ursprünglich auf die Zuordnung zeigen würde, verhielt sich Code, der ein Array vom Typ C deklarierte, durch die Zerlegung von Arrays in Zeiger identisch zu B-Code, der einen Vektor deklariert und dann die Variable, die seine Adresse enthält, nie geändert hat.

Benutzeravatar von glglgl
glglgl

Eigentlich &myarray und myarray beide sind die Basisadresse.

Wenn Sie den Unterschied sehen möchten, anstatt zu verwenden

printf("my_array = %p\n", my_array);
printf("my_array = %p\n", &my_array);

verwenden

printf("my_array = %s\n", my_array);
printf("my_array = %p\n", my_array);

1426050cookie-checkWie kommt es, dass die Adresse eines Arrays gleich seinem Wert in C ist?

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

Privacy policy