Come incrementare l'indirizzo di un puntatore e il valore del puntatore?


96

Supponiamo,

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

Cosa farà effettivamente il codice seguente e come?

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

Lo so, questo è un po 'complicato in termini di codifica, ma voglio sapere cosa accadrà effettivamente quando codificheremo in questo modo.

Nota: supponiamo che l'indirizzo di a=5120300, sia memorizzato nel puntatore il pcui indirizzo è 3560200. Ora, quale sarà il valore p & adopo l'esecuzione di ogni istruzione?


3
perché non lo esegui nel debugger?
AndersK

24
Beh .. perché non provarlo e vedere? printfstamperà un puntatore con% p
Brian Roach

Se sei curioso del comportamento, gioca con esso. Basta scrivere un semplice programma in c che esamini tutti questi casi d'uso e vedere se ha senso per te.
Cyrus

@AndersK. Forse l'OP si aspetta un comportamento indefinito? ...O forse no.
Mateen Ulhaq

Risposte:


175

Per prima cosa, l'operatore ++ ha la precedenza sull'operatore * e gli operatori () hanno la precedenza su tutto il resto.

Secondo, l'operatore numero ++ è lo stesso dell'operatore numero ++ se non li assegni a nulla. La differenza è numero ++ restituisce numero e quindi incrementa numero e ++ numero incrementa prima e poi lo restituisce.

Terzo, aumentando il valore di un puntatore, lo stai incrementando della dimensione del suo contenuto, ovvero lo stai incrementando come se stessi iterando in un array.

Quindi, per riassumere tutto:

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

Poiché ci sono molti casi qui, potrei aver fatto qualche errore, per favore correggimi se sbaglio.

MODIFICARE:

Quindi mi sbagliavo, la precedenza è un po 'più complicata di quello che ho scritto, guardala qui: http://en.cppreference.com/w/cpp/language/operator_precedence


6
* ptr ++, il valore non viene incrementato, il puntatore lo è. Questi operatori unari hanno la stessa precedenza ma vengono valutati da destra a sinistra. Il codice significa "prendi il contenuto da dove punta ptr, quindi incrementa ptr". È un codice C molto comune (e sì, abbastanza confuso). Correggi questo problema e rimuoverò il voto negativo. Lo stesso per * (ptr) ++, la parentesi non fa nulla.
Lundin

Grazie mille Lundin, mi sono perso qualcos'altro?
felipemaia

@ Lundin Ciao, la risposta sopra è stata corretta ora? Grazie.
Unheilig

4
@ Unheilig La prima frase è ancora completamente sbagliata, il suffisso ++ ha la precedenza su unario * che ha la stessa precedenza del prefisso ++. A parte questo, sembra ok.
Lundin

4
@felipemaia Sei sicuro che sarà segfault? Forse è solo un comportamento indefinito?
jotik

13

controllato il programma e i risultati sono come,

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

2
@alex usalo significa per esempio, considera l'istruzione, 'int * a = p ++;' Qui il primo valore del puntatore 'p' verrà utilizzato e dopo di che p si sposterà alla posizione successiva. Quindi, in effetti, dopo aver eseguito l'istruzione precedente, "a" avrà l'indirizzo della posizione precedente puntato da "p" e "p" punterà alla posizione successiva. Cioè, usa prima il valore di 'p' per l'espressione di assegnazione come sopra e poi incrementa il valore di 'p' per puntare alla posizione successiva
Sujith R Kumar

In breve, penso che usi la frase "usalo" per il termine più formale "assegnare". Questo è tutto.
Apekshik Panigrahi

4

Quello che segue è un'istanza dei vari suggerimenti "stampalo". L'ho trovato istruttivo.

#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;
}

Ritorna

(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

Ho lanciato gli indirizzi del puntatore su ints in modo che possano essere facilmente confrontati.

L'ho compilato con GCC.


1
Lo cambierei per includere il valore di xep dopo l'operazione.
NetJohn

3

Riguardo a "Come incrementare un indirizzo del puntatore e il valore del puntatore?" Penso che in ++(*p++);realtà sia ben definito e fa quello che stai chiedendo, ad esempio:

#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;
}

Non sta modificando la stessa cosa due volte prima di un punto della sequenza. Non penso che sia un buon stile per la maggior parte degli usi: è un po 'troppo criptico per i miei gusti.


In realtà, le parentesi non sono necessarie: ++*p++incrementerà con successo sia il valore che il puntatore (il suffisso si ++lega più forte della dereferenziazione *e ciò accade prima del prefisso a ++causa dell'ordine). Le parentesi sono necessarie solo quando è necessario il valore prima di incrementarlo (*p++)++. Se scegli tutto prefisso, ++*++pfunzionerà perfettamente anche senza parentesi (ma incrementa il valore a cui punta dopo l'incremento del puntatore).
cmaster - ripristina 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);

Cos'è l'asociatività?
71GA

1
nel codice puoi vedere * str ++, ora qui sia * che ++ hanno la stessa precedenza (stessa priorità nel termine laico) e anche * str ++ non sono separati usando parentesi come * (str ++) o (* str) ++, quindi diventa necessario come dovrebbe essere valutato. quindi da destra a sinistra significa (x = str ++) e quindi (y = * x)
Abhishek DK
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.