¿Cómo incrementar la dirección de un puntero y el valor del puntero?

96

Supongamos,

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

¿Qué hará realmente el siguiente código y cómo?

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

Lo sé, esto es un poco complicado en términos de codificación, pero quiero saber qué sucederá realmente cuando codifiquemos así.

Nota: Supongamos que la dirección de a=5120300se almacena en el puntero pcuya dirección es 3560200. Ahora bien, ¿cuál será el valor de p & adespués de la ejecución de cada declaración?

Dinesh
fuente
3
¿Por qué no lo ejecuta en el depurador?
AndersK
24
Bueno ... ¿por qué no simplemente probarlo y verlo? printfimprimirá un puntero con% p
Brian Roach
Si tiene curiosidad sobre el comportamiento, simplemente juegue con él. Simplemente escriba un programa c simple que pase por todos estos casos de uso y vea si tiene sentido para usted.
Cyrus
@AndersK. ¿Quizás el OP espera un comportamiento indefinido? ...O tal vez no.
Mateen Ulhaq

Respuestas:

176

Primero, el operador ++ tiene prioridad sobre el operador *, y los operadores () tienen prioridad sobre todo lo demás.

En segundo lugar, el operador de número ++ es el mismo que el operador de número ++ si no los está asignando a nada. La diferencia es número ++ devuelve número y luego incrementa número, y ++ número incrementa primero y luego lo devuelve.

En tercer lugar, al incrementar el valor de un puntero, lo incrementa según el tamaño de su contenido, es decir, lo incrementa como si estuviera iterando en una matriz.

Entonces, para resumirlo todo:

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

Como hay muchos casos aquí, es posible que haya cometido algún error, corríjame si me equivoco.

EDITAR:

Entonces me equivoqué, la precedencia es un poco más complicada de lo que escribí, véalo aquí: http://en.cppreference.com/w/cpp/language/operator_precedence

felipemaia
fuente
6
* ptr ++, el valor no se incrementa, el puntero es. Estos operadores unarios tienen la misma precedencia pero se evalúan de derecha a izquierda. El código significa "tomar el contenido desde donde apunta ptr, luego incrementar ptr". Es un código C muy común (y sí, bastante confuso). Corrija esto y eliminaré el voto negativo. Lo mismo para * (ptr) ++, el paréntesis no hace nada.
Lundin
Muchas gracias Lundin, ¿me perdí algo más?
felipemaia
@Lundin Hola, ¿la respuesta anterior se corrigió ahora? Gracias.
Unheilig
4
@Unheilig La primera oración sigue siendo completamente incorrecta, postfix ++ tiene prioridad sobre unario * que tiene la misma precedencia que prefix ++. Aparte de eso, parece estar bien.
Lundin
4
@felipemaia ¿Estás seguro de que segfault? ¿Quizás es solo un comportamiento indefinido?
jotik
13

comprobado el programa y los resultados son como,

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
fuente
2
@alex use significa, por ejemplo, considerar declaración, 'int * a = p ++;' Aquí se utilizará el primer valor del puntero 'p' y, después, p se moverá a la siguiente posición. Entonces, en efecto, después de ejecutar la declaración anterior, 'a' tendrá la dirección de la ubicación anterior señalada por 'p' y 'p' señalará a la siguiente posición. Es decir, primero use el valor de 'p' para la expresión de asignación como se
muestra
En resumen, creo que usa la frase "úsala" para el término más formal "asignar". Eso es todo.
Apekshik Panigrahi
4

La siguiente es una instanciación de las diversas sugerencias de "solo imprímalo". Lo encontré instructivo.

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

Vuelve

(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

Lanzo las direcciones de puntero a ints para que puedan compararse fácilmente.

Lo compilé con GCC.

Rico Picone
fuente
1
Cambiaría esto para incluir el valor de xyp después de la operación.
NetJohn
3

Con respecto a "¿Cómo incrementar la dirección y el valor de un puntero?" Creo que en ++(*p++);realidad está bien definido y hace lo que está pidiendo, por ejemplo:

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

No es modificar lo mismo dos veces antes de un punto de secuencia. Sin embargo, no creo que sea de buen estilo para la mayoría de los usos, es un poco demasiado críptico para mi gusto.

Flexo
fuente
En realidad, los paréntesis son innecesarios: ++*p++incrementará con éxito tanto el valor como el puntero (el sufijo se ++une más fuerte que la desreferencia *, y eso sucede antes del prefijo ++debido al orden). Los paréntesis solo son necesarios cuando necesita el valor antes de incrementarlo (*p++)++. Si elige todos los prefijos, ++*++ptambién funcionará bien sin paréntesis (pero incrementa el valor al que se apunta después del incremento del puntero).
cmaster - reinstalar a 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
fuente
¿Qué es la asociatividad?
71GA
1
en el código puede ver el * str ++, ahora aquí tanto * como ++ tienen la misma prioridad (la misma prioridad en términos simples) y también * str ++ no están separados usando paréntesis como * (str ++) o (* str) ++, entonces se hace necesario cómo debe evaluarse. entonces de derecha a izquierda significa (x = str ++) y luego (y = * x)
Abhishek DK