[Gelöst] Inhalt des Arrays mit Zeiger verändern



  • Hallo!

    Ich verstehe einige Stellen in diesem Code nicht:

    #include <stdio.h>
    
    int main()
    {
        int i = 0;
        int a[] = {0, 1, 2, 3, 4, 5, 6};
        int *p = a;
        *(p+1) = 0;
        printf("p: %d\n", p);
        printf("&p: %d\n", &p);
        p += 3;
    
        while(i<7)
        {
            printf("%2d", *(p+i));
            i++;
        }
    
        return 1;
    }
    

    1. Warum liefern:

    printf("p: %d\n", p);
        printf("&p: %d\n", &p);
    

    unterschiedliche Ausgaben?

    p: 2686704
    &p: 2686700
    

    Wenn ich richtig verstanden habe, liefert &p die Adresse vom ersten Element des Arrays im Arbeitsspeicher (also &p entspricht der Adresse von a[0])? Was macht dann p (ohne Adressoperator)?

    2. Was passiert hier?

    p += 3;
    

    Nach dieser Zeile ist mein Array "zerstört" und liefert diese komische Ausgabe:

    0 4 5 6 442002562130567168
    

    Vielen Dank!



  • printf("p: %d\n", p);
    

    Druckt den Inhalt des Zeigers p.

    printf("p: %d\n", &p);
    

    Druckt die Adresse des Zeigers p.

    Das aber nur dann, wenn sizeof( int ) == sizeof( int * )

    Bei einem 64-Bit System könntest Du damit falsche Ergebnisse bekommen.

    Nach dieser Zeile

    p += 3;
    

    Verweist p nicht mehr auf das erste Element Deines Arrays, sondern auf das vierte Element. Dein Array ist deswegen nicht zerstört, nur greifst Du halt bei

    printf("%2d", *(p+i));
    

    Für i > 3 auf nicht definierte Bereiche zu.

    mfg Martin



  • Hallo und danke für deine Antwort.

    Druckt den Inhalt des Zeigers p.

    Das habe ich leider nicht verstanden. Ich dachte immer, dass der Inhalt eines Zeigers den Werten entspricht, die dort gespeichert sind? Also in meinem Fall 0,1,2,3,4,5,6.

    Bei einem Pointer, der auf eine Variable zeigt, erhalte ich den Wert der Variable:

    int t = 5;
        int *tp = t;
    
        printf("%d\n", tp);
    
    5
    

    Und in meinem Beispiel oben eine komische lange Zahl, die fast wie die Adresse des Zeigers aussieht.

    Das aber nur dann, wenn sizeof( int ) == sizeof( int * )

    Bei einem 64-Bit System könntest Du damit falsche Ergebnisse bekommen.

    Leider auch nicht verstanden. Kann ich auf einem 64-Bit System eine falsche Adresse bekommen? Sollte der Zeiger nicht immer auf die richtige Adresse im Speicher zeigen?



  • forumnewbie schrieb:

    Hallo und danke für deine Antwort.

    Druckt den Inhalt des Zeigers p.

    Das habe ich leider nicht verstanden. Ich dachte immer, dass der Inhalt eines Zeigers den Werten entspricht, die dort gespeichert sind? Also in meinem Fall 0,1,2,3,4,5,6.

    Bei einem Pointer, der auf eine Variable zeigt, erhalte ich den Wert der Variable:

    int t = 5;
        int *tp = t;
    
        printf("%d\n", tp);
    
    5
    

    Und in meinem Beispiel oben eine komische lange Zahl, die fast wie die Adresse des Zeigers aussieht.

    Das aber nur dann, wenn sizeof( int ) == sizeof( int * )

    Bei einem 64-Bit System könntest Du damit falsche Ergebnisse bekommen.

    Leider auch nicht verstanden. Kann ich auf einem 64-Bit System eine falsche Adresse bekommen? Sollte der Zeiger nicht immer auf die richtige Adresse im Speicher zeigen?

    Schaue Dir einfach mal die Bedeutung des Adressoperators (&) und des Dereferenzoperators (*) an und wie sie benutzt werden. So wie Du das machst, ist das völliger Unfug.

    So macht man's besser:

    int t=5;
    int *tp = &t;
    
    printf( "%p %d\n", tp, *tp );
    

    Auf einem 64-Bit-system ist ein Zeiger i.d.R. 64 Bit lang, ein int aber nur 32. Beim printf mit dem Format %d wird daher eine 32-Bit Zahl erwartet und ausgegeben, du übergibst aber eine 64-Bit adresse

    mfg Martin



  • Hier funktioniert deine Zuordnung, weil der Name des Arrays ein Zeiger auf das 1. Element ist.

    int a[] = {0, 1, 2, 3, 4, 5, 6};
    int *p = a;
    

    Hier ordnest du dem Inhalt der Variablen einen Zeiger zu. Das funktioniert nicht.
    Wie schon gesagt wurde, braucht t den Adressoperator.

    int t = 5;
    int *tp = t;    // int *tp = &t;
    


  • Danke für den Hinweis!
    Also ich habe das jetzt folgendermaßen verstanden: mit dem Adressoperator (&) erhalte ich die Stelle im Arbeitsspeicher, wo eine Variable liegt. Wenn ich wissen will, welcher Wert unter dieser Adresse im Arbeitsspeicher gespeichert ist, dann benutze ich den Dereferenzierungsoperator (*).
    Wenn ich also einem Zeiger eine Variable zuweisen will, dann muss ich das über ihre Adresse im Arbeitsspeicher machen, deshalb:

    int varp* = &var;
    

    Und beim Array klappt die Zuweisung ohne Adressoperator, weil das Array a automatisch auf die Adresse des ersten Elements zeigt. Deshalb ist:

    int a[] = {0, 1, 2, 3, 4, 5, 6};
    int *p = a;
    

    dasselbe wie:

    int *p = &a;
    

    Wenn ich eine Adresse eines Zeigers (und Arrays) herausfinden will, dann brauche ich keinen Adressoperator mehr, da ein Zeiger selbst die Adresse des ersten Elements ist:

    printf("p: %d\n", p);
    

    Array ohne Indexangabe ist ebenfalls einfach die Adresse des ersten Elements, der in dem Array gespeichert ist.
    Will ich jetzt den Wert vom ersten Element haben, dann kann jetzt den Dereferenzierungsoperator verwenden:

    printf("Element 0: %d\n", *p);
    

    Oder einfach:

    printf("Element 0: %d\n", a[0]);
    

    Nur bei einer Variable benötige ich den Adressoperator, wenn ich ihre Adresse anzeigen will:

    printf("var: %d\n", &var);
    

    Habe ich das jetzt alles richtig aufgeschrieben bzw. verstanden?



  • printf() braucht %p als Spezifizierer um einen Zeiger anzuzeigen, nicht %d.

    Die Adresse wird dannn hexadezimal ausgegeben.

    int varp* = &var;
    

    Das ist nicht richtig, der Stern muss vor das varp.



  • forumnewbie schrieb:

    dasselbe wie:
    C:

    int *p = &a;
    

    Nein.
    Das ist

    int *p = &a[0];
    

    Du kannst ein Array auch in der Zeigerart ansprechen und umgekehrt:#

    int a[10];
    int *p = a;
    printf("Element 0: %d\n", *p);
    printf("Element 0: %d\n", p[0]);
    printf("Element 0: %d\n", *a);
    printf("Element 0: %d\n", a[0]);
    

    gibt dir jedesmal das Erste Element von a aus.
    Falls du jetzt denkst, das Array und Zeiger das Selbe sind: NEIN.

    Du kannst einmal einem Array keinen anderen Speicher zuweisen.

    a = p; // geht nicht.
    

    Und sizeof() gibt beim Zeiger die Größe des Zeigers und nicht die Größe des Speichers auf den er zeigt.

    Und wenn du ein Array an eine Funktion übergibst, sieht die Funktion einen Zeiger.



  • Vielen Dank!

    Ich hoffe, dass ich das jetzt richtig verstanden habe. Hat mir auf jeden Fall sehr weitergeholfen. 👍



  • forumnewbie schrieb:

    Danke für den Hinweis!
    Also ich habe das jetzt folgendermaßen verstanden: mit dem Adressoperator (&) erhalte ich die Stelle im Arbeitsspeicher, wo eine Variable liegt. Wenn ich wissen will, welcher Wert unter dieser Adresse im Arbeitsspeicher gespeichert ist, dann benutze ich den Dereferenzierungsoperator (*).
    Wenn ich also einem Zeiger eine Variable zuweisen will, dann muss ich das über ihre Adresse im Arbeitsspeicher machen, deshalb:

    int varp* = &var;
    

    So ist's richtig:

    int *varp = &var;
    

    forumnewbie schrieb:

    Und beim Array klappt die Zuweisung ohne Adressoperator, weil das Array a automatisch auf die Adresse des ersten Elements zeigt. Deshalb ist:

    int a[] = {0, 1, 2, 3, 4, 5, 6};
    int *p = a;
    

    dasselbe wie:

    int *p = &a;
    

    Bin mir jetzt nicht sicher, ob das erlaubt ist. Richtig ist jedenfalls: Der Name eines Arrays ohne Indexoperator ist die Adresse des ersten Elements. Er kann wie ein Zeiger benutzt werden außer, daß er KEIN LVALUE ist, also nicht verändert werden kann.

    forumnewbie schrieb:

    Wenn ich eine Adresse eines Zeigers (und Arrays) herausfinden will, dann brauche ich keinen Adressoperator mehr, da ein Zeiger selbst die Adresse des ersten Elements ist:

    printf("p: %d\n", p);
    

    Array ohne Indexangabe ist ebenfalls einfach die Adresse des ersten Elements, der in dem Array gespeichert ist.

    Fast. Ein Zeiger ist eine ganz normale Variable und hat deshalb auch eine Adresse, die mit dem Adressoperator ermittelt werden kann.

    forumnewbie schrieb:

    Will ich jetzt den Wert vom ersten Element haben, dann kann jetzt den Dereferenzierungsoperator verwenden:

    printf("Element 0: %d\n", *p);
    

    Oder einfach:

    printf("Element 0: %d\n", a[0]);
    

    Nur bei einer Variable benötige ich den Adressoperator, wenn ich ihre Adresse anzeigen will:

    printf("var: %d\n", &var);
    

    Habe ich das jetzt alles richtig aufgeschrieben bzw. verstanden?

    Für Adressen wird das Format %p benutzt.

    printf("var: %p\n", &var);
    

    Das ist vor allen auf 64-Bit-Systemen wichtig, wie ich schon mal schrieb.,

    Ansonsten, Du bewegst dich jedenfalls in die richtige Richtung.

    Das Problem, warum das so viele durcheinander bringen ist, daß
    1. Der Name des Arrays wie ein Zeiger benutzt werden kann
    2. Funktionen kein Array übergeben bekommen, sondern nur deren Adresse.

    Deshalb bringen viele die Begriffe Array, Adresse und Zeiger durcheinander.

    Ein Zeiger ist aber ein LValue, ein Array aber nicht. LValues haben grundsätzlich Adressen, die mit dem Adressoperator ermittelt werden.

    mfg Martin


Anmelden zum Antworten