Warum ein Zeiger + 1 eigentlich 4 addiert

Lesezeit: 5 Minuten
#include<stdio.h>
int main(void){
  int *ptr,a,b;
  a = ptr;
  b = ptr + 1;
  printf("the vale of a,b is %x and %x respectively",a,b);

  int c,d;
  c = 0xff;
  d = c + 1;
  printf("the value of c d are %x and %x respectively",c,d);
  return 0;
}

der Ausgangswert ist

the vale of a,b is 57550c90 and 57550c94 respectively
the value of c d are ff and 100 respectively%  

es stellt sich heraus das ptr + 1 tatsächlich, warum es sich so verhält?

  • Siehe meine vorherige Antwort auf eine Frage wie diese.

    – Jonathon Reinhart

    22. Juli 2012 um 7:14 Uhr

  • Du solltest benutzen %p in printf Formatstrings für Zeiger. Nicht verwenden %x dafür ist es nicht portabel (weil Zeiger und int-s kann eine andere Bitbreite haben).

    – Basile Starynkevitch

    22. Juli 2012 um 8:12 Uhr


  • Sie sollten wirklich alle Warnungen für Ihren Compiler aktivieren, z -Wall wenn mit kompilieren gcc; Ihr Code enthält mehrere Fehler! Im Speziellen ptr bleibt nicht initialisiert, wird aber verwendet (undefiniertes Verhalten).

    – Basile Starynkevitch

    22. Juli 2012 um 8:20 Uhr


  • @BasileStarynkevitch Ja, du hast recht. Ich überprüfe nur die %xund ‘%p’ gibt es einen Unterschied. Und für den Clang-Compiler kann es auch verwendet werden -Wall Warnung aktivieren?

    – mko

    22. Juli 2012 um 8:28 Uhr

Weil Zeiger so konzipiert sind, dass sie mit Arrays kompatibel sind:

*(pointer + offset)

ist äquivalent zu

pointer[offset]

Zeigerarithmetik funktioniert also nicht in Bezug auf Bytes, sondern in Bezug auf sizeof(pointer base type)-Bytes große Blöcke.

  • für 64-Bit-Maschinen kann es bis zu 8 Bytes groß sein.

    – Nachnix

    22. Juli 2012 um 7:10 Uhr

  • @Aftnix ja, aber was ist das Problem daran?

    Benutzer529758

    22. Juli 2012 um 7:11 Uhr

  • ein Zeiger ist groß genug, um eine Speicheradresse der Plattform aufzunehmen. Wenn Sie 8 Bytes benötigen, um die Speicheradresse zu speichern, sind es 8 Bytes, unabhängig davon, worauf es zeigt. Ich sage nur, dass Sie der Allgemeinheit halber in Ihrer Antwort darauf hinweisen sollten. An Ihrer Antwort ist nichts auszusetzen, aber die Zeigerarithmetik ist sinnvoll, wenn Sie eine Zeigervariable mit “fester” Größe haben. Ich sage nur, bevor Sie das Prinzip der Zeigerarithmetik erläutern, sollten Sie sagen, dass jede Plattform eine native feste Zeigergröße hat. Aus diesem Grund ist die Zeigerarithmetik auf verschiedenen Plattformen konsistent.

    – Nachnix

    22. Juli 2012 um 7:20 Uhr

  • +1, um mich über die Verbindung zwischen Array und Zeiger zu informieren. aber ich kann Ihren Code nicht zum Laufen bringen: printf(“%p”,ptr[1])

    – mko

    22. Juli 2012 um 8:22 Uhr

  • eh nicht, printf(“%p”, ptr + 1). Beachten Sie, dass *(ptr + offset) ist äquivalent zu ptr[offset]aber ptr + offset selbst ist nicht!

    Benutzer529758

    22. Juli 2012 um 10:04 Uhr

Benutzeravatar von Yevgeny Simkin
Jewgeni Simkin

Überlegen Sie, was ein Zeiger ist … es ist eine Speicheradresse. Jedes Byte im Speicher hat eine Adresse. Wenn Sie also eine haben int das sind 4 Bytes und seine Adresse ist 1000, 1001 ist eigentlich das 2. Byte davon int und 1002 ist das dritte Byte und 1003 ist das vierte. Da die Größe eines int von Compiler zu Compiler variieren kann, ist es zwingend erforderlich, dass Sie beim Erhöhen Ihres Zeigers nicht die Adresse eines Mittelpunkts in der erhalten int. Die Aufgabe, basierend auf Ihrem Datentyp herauszufinden, wie viele Bytes zu überspringen sind, wird also für Sie erledigt, und Sie können einfach den Wert verwenden, den Sie erhalten, und sich nicht darum kümmern.

Wie Basile Starynkvitch betont, variiert dieser Betrag je nach dem sizeof Eigenschaft des Datenelements, auf das gezeigt wird. Es ist sehr leicht zu vergessen, dass, obwohl Adressen sequenziell sind, die Zeiger Ihrer Objekte den tatsächlichen Speicherplatz berücksichtigen müssen, der zum Unterbringen dieser Objekte erforderlich ist.

Benutzeravatar von Basile Starynkevitch
Basile Starynkevitch

Zeigerarithmetik ist ein heikles Thema. Eine Zeigeraddition bedeutet den Übergang zu einem nächsten Element, auf das gezeigt wird. Die Adresse wird also um den inkrementiert sizeof das spitze Element.

Benutzeravatar von OMGtechy
OMGtechy

Kurze Antwort

Die Adresse des Pointers wird um inkrementiert sizeof(T) wo T ist der Typ, auf den gezeigt wird. Also für ein intwird der Zeiger um inkrementiert sizeof(int).

Wieso den?

Nun, in erster Linie verlangt es die Norm. Der Grund, warum dieses Verhalten nützlich ist (abgesehen von der Kompatibilität mit C), liegt darin, dass Sie eine Datenstruktur haben, die zusammenhängenden Speicher verwendet, wie ein Array oder eine std::vector, können Sie zum nächsten Element im Array wechseln, indem Sie einfach eins zum Zeiger hinzufügen. Wenn Sie zum n-ten Element im Container wechseln möchten, fügen Sie einfach n hinzu.

Schreiben können firstAddress + 2 ist viel einfacher als firstAddress + (sizeof(T) * 2)und hilft, Fehler zu vermeiden, die durch die Annahme von Entwicklern entstehen sizeof(int) ist 4 (möglicherweise nicht) und schreibt Code wie firstAddress + (4 * 2).

In der Tat, wenn Sie sagen myArray[4]du sagst myArray + 4. Aus diesem Grund beginnen Array-Indizes bei 0; Sie addieren einfach 0, um das erste Element zu erhalten (dh myArray zeigt auf das erste Element des Arrays) und n, um das n-te zu erhalten.

Was ist, wenn ich jeweils ein Byte verschieben möchte?

sizeof(char) ist garantiert ein Byte groß, sodass Sie a verwenden können char* wenn Sie wirklich ein Byte auf einmal verschieben möchten.

Ein Zeiger wird verwendet, um auf ein bestimmtes Speicherbyte zu zeigen, das markiert, wo ein Objekt zugewiesen wurde (technisch gesehen kann er überall hin zeigen, aber so wird er verwendet). Wenn Sie Zeigerarithmetik durchführen, arbeitet sie basierend auf der Größe der Objekte, auf die gezeigt wird. In Ihrem Fall ist es ein Zeiger auf ganze Zahlen, die jeweils eine Größe von 4 Bytes haben.

Benutzeravatar von md5
md5

Betrachten wir einen Zeiger p. Der Ausdruck p+n ist wie (unsigned char *)p + n * sizeof *p (Weil sizeof(unsigned char) == 1). Versuche dies :

#include <stdio.h>
#define N   3

int
main(void)
{
    int i;
    int *p = &i;
    printf("%p\n", (void *)p);
    printf("%p\n", (void *)(p + N));
    printf("%p\n", (void *)((unsigned char *)p + N * sizeof *p));
    return 0;
}

1386400cookie-checkWarum ein Zeiger + 1 eigentlich 4 addiert

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

Privacy policy