Colocación del asterisco en las declaraciones del puntero

Recientemente decidí que solo tenía que aprender finalmente C / C ++, y hay una cosa que realmente no entiendo acerca de los punteros o, más precisamente, su definición.

¿Qué tal estos ejemplos?

  1. int* test;
  2. int *test;
  3. int * test;
  4. int* test,test2;
  5. int *test,test2;
  6. int * test,test2;

Ahora, a mi entender, los primeros tres casos están haciendo lo mismo: Test no es un int, sino un puntero a uno.

El segundo conjunto de ejemplos es un poco más complicado. En el caso 4, tanto test como test2 serán punteros a un int, mientras que en el caso 5, solo test es un puntero, mientras que test2 es un int “real”. ¿Qué pasa con el caso 6? Igual que el caso 5?

4, 5 y 6 son lo mismo, solo la prueba es un puntero. Si desea dos punteros, debe usar:

 int *test, *test2; 

O, incluso mejor (para aclarar todo):

 int* test; int* test2; 

El espacio en blanco alrededor de los asteriscos no tiene importancia. Los tres significan lo mismo:

 int* test; int *test; int * test; 

El ” int *var1, var2 ” es una syntax maligna que solo pretende confundir a las personas y debe evitarse. Se expande a:

 int *var1; int var2; 

Utilice la “Regla de espiral en el sentido de las agujas del reloj” para ayudar a analizar las declaraciones de C / C ++;

Hay tres pasos simples a seguir:

  1. Comenzando con el elemento desconocido, mueva en una dirección espiral / a la derecha; cuando encuentre los siguientes elementos, reemplácelos con las declaraciones inglesas correspondientes:

    [X] o [] : Array X size of … or Array undefined size of …

    (type1, type2) : la función pasa tipo1 y tipo2 devuelve …

    * : puntero (s) para …

  2. Siga haciendo esto en sentido espiral / horario hasta que todos los tokens hayan sido cubiertos.
  3. ¡Siempre resuelve todo entre paréntesis primero!

Además, las declaraciones deben estar en declaraciones separadas cuando sea posible (lo cual es cierto la gran mayoría de las veces).

Muchas pautas de encoding recomiendan que solo declare una variable por línea . Esto evita cualquier confusión del tipo que tenías antes de hacer esta pregunta. La mayoría de los progtwigdores de C ++ con los que he trabajado parecen seguir con esto.


Un poco aparte, lo sé, pero algo que encontré útil es leer las declaraciones al revés.

 int* test; // test is a pointer to an int 

Esto comienza a funcionar muy bien, especialmente cuando comienzas a declarar const pointers y es difícil saber si es el puntero const, o si es a lo que apunta el puntero que es const.

 int* const test; // test is a const pointer to an int int const * test; // test is a pointer to a const int ... but many people write this as const int * test; // test is a pointer to an int that's const 

Como otros mencionaron, 4, 5 y 6 son lo mismo. A menudo, las personas usan estos ejemplos para argumentar que * pertenece a la variable en lugar del tipo. Si bien es un problema de estilo, existe cierto debate sobre si debes pensar y escribir de esta manera:

 int* x; // "x is a pointer to int" 

o de esta manera:

 int *x; // "*x is an int" 

FWIW Estoy en el primer campamento, pero la razón por la que otros hacen el argumento para la segunda forma es que (principalmente) resuelve este problema en particular:

 int* x,y; // "x is a pointer to int, y is an int" 

que es potencialmente engañoso; en su lugar, escribirías

 int *x,y; // it's a little clearer what is going on here 

o si realmente quieres dos punteros,

 int *x, *y; // two pointers 

Personalmente, digo que se mantenga en una variable por línea, entonces no importa qué estilo prefiera.

 #include  std::add_pointer::type test, test2; 

En 4, 5 y 6, la test siempre es un puntero y test2 no es un puntero. El espacio en blanco es (casi) nunca significativo en C ++.

El puntero es un modificador del tipo. Lo mejor es leerlos de derecha a izquierda para comprender mejor cómo el asterisco modifica el tipo. ‘int *’ puede leerse como “puntero a int ‘. En declaraciones múltiples debe especificar que cada variable sea un puntero o se creará como una variable estándar.

1,2 y 3) La prueba es de tipo (int *). El espacio en blanco no importa.

4,5 y 6) La prueba es de tipo (int *). Test2 es de tipo int. De nuevo, el espacio en blanco es inconsecuente.

Puede pensar en 4, 5 y 6 de la siguiente manera: declarar el tipo solo tiene que hacerse una vez, pero si quiere declarar un puntero a ese tipo (agregando un asterisco), debe hacerlo para cada variable.

Al declarar una variable de puntero, siempre agrego espacios en blanco entre la variable y el asterisco, incluso si declaro más de uno en una línea. No hacerlo me hace confundirlo con una expresión de desreferenciación casi siempre.

La razón en C es que declaras las variables de la forma en que las usas. Por ejemplo

 char *a[100]; 

dice que *a[42] será un char . Y a[42] un puntero char. Y así a es una matriz de punteros de char.

Esto porque los escritores originales del comstackdor querían usar el mismo analizador para expresiones y declaraciones. (No es una razón muy sensata para una elección de diseño de langage)

Yo diría que la convención inicial era poner la estrella en el lado del nombre del puntero (lado derecho de la statement

Puedes seguir las mismas reglas, pero no es gran cosa si pones estrellas en el lado tipo. Recuerde que la coherencia es importante, por lo que siempre, pero la estrella en el mismo lado, independientemente de qué lado tiene que elegir.

Una buena regla empírica, mucha gente parece entender estos conceptos de la siguiente manera: en C ++, un gran significado semántico se deriva del enlace de la izquierda de palabras clave o identificadores.

Toma por ejemplo:

 int const bla; 

La const se aplica a la palabra “int”. Lo mismo ocurre con los asteriscos de los indicadores, que se aplican a la palabra clave que les queda. Y el nombre de la variable real? Sí, eso está declarado por lo que queda de él.

Los casos 1, 2 y 3 son iguales, declaran punteros a las variables int. Los casos 3, 4 y 5 son los mismos, ya que declaran un puntero a, y una variable int respectivamente. Si desea declarar dos punteros en una línea (que no debería), debe poner un asterisco delante de cada nombre de variable:

 int *test, *test2; 

No hay una cierta forma correcta que diga adónde va el asterisco. int* test ve mejor porque nos resulta más fácil imaginar que anexar * al final de un tipo significa “señalar a” ese tipo. Sin embargo, la int *test tiene más sentido, porque puede trabajar con ella como el signo menos en matemáticas:

 -(-x) = x 

es análogo a

 *(*test) = test 

Esto siempre me ha ayudado. Lamentablemente, el resultado de todo es que a veces uso int* test y, a veces int *test .