Wie inkrementiere ich eine Zeigeradresse und einen Zeigerwert?

88

Lasst uns annehmen,

int *p;
int a = 100;
p = &a;

Was macht der folgende Code eigentlich und wie?

p++;
++p;
++*p;
++(*p);
++*(p);
*p++;
(*p)++;
*(p)++;
*++p;
*(++p);

Ich weiß, das ist in Bezug auf die Codierung etwas chaotisch, aber ich möchte wissen, was tatsächlich passieren wird, wenn wir so codieren.

Hinweis: Nehmen wir an, dass die Adresse von a=5120300in einem Zeiger gespeichert ist, pdessen Adresse lautet 3560200. Was ist nun der Wert p & anach der Ausführung jeder Anweisung?

Dinesh
quelle
3
Warum führen Sie es nicht einfach im Debugger aus?
AndersK
23
Nun ... warum nicht einfach versuchen und sehen? printfwird einen Zeiger mit% p drucken
Brian Roach
Wenn Sie neugierig auf Verhalten sind, spielen Sie einfach damit herum. Schreiben Sie einfach ein einfaches c-Programm, das alle diese Anwendungsfälle durchläuft, und prüfen Sie, ob es für Sie sinnvoll ist.
Cyrus
@AndersK. Vielleicht erwartet das OP undefiniertes Verhalten? ...Oder vielleicht nicht.
Mateen Ulhaq

Antworten:

164

Erstens hat der Operator ++ Vorrang vor dem Operator *, und die Operatoren () haben Vorrang vor allem anderen.

Zweitens ist der ++ - Zahlenoperator der gleiche wie der Zahl ++ - Operator, wenn Sie sie nichts zuweisen. Der Unterschied besteht darin, dass Zahl ++ die Zahl zurückgibt und dann die Zahl erhöht, und die Zahl ++ zuerst erhöht und dann zurückgibt.

Drittens erhöhen Sie den Wert eines Zeigers, indem Sie ihn um die Größe seines Inhalts erhöhen, dh, Sie erhöhen ihn, als würden Sie in einem Array iterieren.

Um es zusammenzufassen:

ptr++;    // Pointer moves to the next int position (as if it was an array)
++ptr;    // Pointer moves to the next int position (as if it was an array)
++*ptr;   // The value of ptr is incremented
++(*ptr); // The value of ptr is incremented
++*(ptr); // The value of ptr is incremented
*ptr++;   // Pointer moves to the next int position (as if it was an array). But returns the old content
(*ptr)++; // The value of ptr is incremented
*(ptr)++; // Pointer moves to the next int position (as if it was an array). But returns the old content
*++ptr;   // Pointer moves to the next int position, and then get's accessed, with your code, segfault
*(++ptr); // Pointer moves to the next int position, and then get's accessed, with your code, segfault

Da es hier viele Fälle gibt, habe ich möglicherweise einen Fehler gemacht. Bitte korrigieren Sie mich, wenn ich falsch liege.

BEARBEITEN:

Ich habe mich also geirrt, der Vorrang ist etwas komplizierter als das, was ich geschrieben habe. Sehen Sie ihn hier an: http://en.cppreference.com/w/cpp/language/operator_precedence

Felipemaia
quelle
6
* ptr ++, der Wert wird nicht erhöht, der Zeiger ist. Diese unären Operatoren haben dieselbe Priorität, werden jedoch von rechts nach links ausgewertet. Der Code bedeutet "Nehmen Sie den Inhalt von der Stelle, auf die ptr zeigt, und erhöhen Sie dann ptr". Es ist sehr häufiger C-Code (und ja, ziemlich verwirrend). Bitte korrigieren Sie dies und ich werde die Ablehnung entfernen. Wie bei * (ptr) ++ tut die Klammer nichts.
Lundin
Vielen Dank Lundin, habe ich noch etwas vermisst?
Felipemaia
@Lundin Hallo, ist die obige Antwort jetzt korrigiert? Vielen Dank.
Unheilig
4
@Unheilig Der erste Satz ist immer noch völlig falsch, Postfix ++ hat Vorrang vor unary *, das den gleichen Vorrang wie Präfix ++ hat. Abgesehen davon scheint es in Ordnung zu sein.
Lundin
3
@felipemaia Bist du sicher, dass es fehlerhaft wird? Vielleicht ist es nur undefiniertes Verhalten?
Jotik
12

überprüfte das Programm und die Ergebnisse sind wie folgt:

p++;    // use it then move to next int position
++p;    // move to next int and then use it
++*p;   // increments the value by 1 then use it 
++(*p); // increments the value by 1 then use it
++*(p); // increments the value by 1 then use it
*p++;   // use the value of p then moves to next position
(*p)++; // use the value of p then increment the value
*(p)++; // use the value of p then moves to next position
*++p;   // moves to the next int location then use that value
*(++p); // moves to next location then use that value
Sujith R Kumar
quelle
2
@alex use bedeutet beispielsweise, dass die Anweisung 'int * a = p ++;' Hier wird der erste Wert des Zeigers 'p' verwendet und danach bewegt sich p zur nächsten Position. In der Tat hat 'a' nach dem Ausführen der obigen Anweisung die Adresse der vorherigen Position, auf die 'p' zeigt, und 'p' zeigt auf die nächste Position. Das heißt, verwenden Sie zuerst den Wert von 'p' für den Zuweisungsausdruck wie oben und
erhöhen Sie
Kurz gesagt, ich denke, er verwendet den Ausdruck "benutze es" für den formelleren Begriff "zuweisen". Das ist alles.
Apekshik Panigrahi
4

Das Folgende ist eine Instanziierung der verschiedenen Vorschläge zum Ausdrucken. Ich fand es lehrreich.

#include "stdio.h"

int main() {
    static int x = 5;
    static int *p = &x;
    printf("(int) p   => %d\n",(int) p);
    printf("(int) p++ => %d\n",(int) p++);
    x = 5; p = &x;
    printf("(int) ++p => %d\n",(int) ++p);
    x = 5; p = &x;
    printf("++*p      => %d\n",++*p);
    x = 5; p = &x;
    printf("++(*p)    => %d\n",++(*p));
    x = 5; p = &x;
    printf("++*(p)    => %d\n",++*(p));
    x = 5; p = &x;
    printf("*p++      => %d\n",*p++);
    x = 5; p = &x;
    printf("(*p)++    => %d\n",(*p)++);
    x = 5; p = &x;
    printf("*(p)++    => %d\n",*(p)++);
    x = 5; p = &x;
    printf("*++p      => %d\n",*++p);
    x = 5; p = &x;
    printf("*(++p)    => %d\n",*(++p));
    return 0;
}

Es kehrt zurück

(int) p   => 256688152
(int) p++ => 256688152
(int) ++p => 256688156
++*p      => 6
++(*p)    => 6
++*(p)    => 6
*p++      => 5
(*p)++    => 5
*(p)++    => 5
*++p      => 0
*(++p)    => 0

Ich habe die Zeigeradressen auf geworfen int s gesetzt, damit sie leicht verglichen werden können.

Ich habe es mit GCC zusammengestellt.

Rico Picone
quelle
Ich würde dies ändern, um den Wert von x und p nach der Operation einzuschließen.
NetJohn
3

In Bezug auf "Wie inkrementiere ich eine Zeigeradresse und einen Zeigerwert?" Ich denke, das ++(*p++);ist eigentlich gut definiert und macht das, wonach Sie fragen, zB:

#include <stdio.h>

int main() {
  int a = 100;
  int *p = &a;
  printf("%p\n",(void*)p);
  ++(*p++);
  printf("%p\n",(void*)p);
  printf("%d\n",a);
  return 0;
}

Es wird nicht zweimal vor einem Sequenzpunkt dasselbe geändert. Ich denke nicht, dass es für die meisten Zwecke ein guter Stil ist - es ist ein bisschen zu kryptisch für meinen Geschmack.

Flexo
quelle
Tatsächlich sind die Klammern nicht erforderlich: ++*p++Inkrementiert erfolgreich sowohl den Wert als auch den Zeiger (Postfix ++bindet stärker als Dereferenzierung *, und dies geschieht ++aufgrund der Reihenfolge vor dem Präfix ). Die Klammern sind nur erforderlich, wenn Sie den Wert vor dem Inkrementieren benötigen (*p++)++. Wenn Sie alle Präfixe verwenden, ++*++pfunktioniert dies auch ohne Klammern einwandfrei (erhöhen Sie jedoch den Wert, auf den nach dem Zeigerinkrement verwiesen wird).
cmaster - wieder einsetzen Monica
1
        Note:
        1) Both ++ and * have same precedence(priority), so the associativity comes into picture.
        2) in this case Associativity is from **Right-Left**

        important table to remember in case of pointers and arrays: 

        operators           precedence        associativity

    1)  () , []                1               left-right
    2)  *  , identifier        2               right-left
    3)  <data type>            3               ----------

        let me give an example, this might help;

        char **str;
        str = (char **)malloc(sizeof(char*)*2); // allocate mem for 2 char*
        str[0]=(char *)malloc(sizeof(char)*10); // allocate mem for 10 char
        str[1]=(char *)malloc(sizeof(char)*10); // allocate mem for 10 char

        strcpy(str[0],"abcd");  // assigning value
        strcpy(str[1],"efgh");  // assigning value

        while(*str)
        {
            cout<<*str<<endl;   // printing the string
            *str++;             // incrementing the address(pointer)
                                // check above about the prcedence and associativity
        }
        free(str[0]);
        free(str[1]);
        free(str);
Abhishek DK
quelle
Was ist Asoziativität?
71GA
1
Im Code sehen Sie * str ++, jetzt haben hier sowohl * als auch ++ die gleiche Priorität (gleiche Priorität im Laienbegriff) und auch * str ++ werden nicht durch Klammern wie * (str ++) oder (* str) ++ getrennt es wird notwendig, wie es bewertet werden soll. also bedeutet von rechts nach links (x = str ++) und dann (y = * x)
Abhishek DK