2010-09-28 23 views
8

Sólo se me ocurrió que no sé cómo inicializar un puntero a puntero desde un valor que no sea puntero con una declaración en C++:puntero Inicializar a puntero con múltiples operadores de dirección en C o C++

int a = 1; 
int** ppa = &&a; //Does not compile 
int** ppa = &(&a); //Does not compile 
int* pa = &a; //Works but is a 
int** ppa = &pa; //Two step solution 

¿Me estoy perdiendo algo, es la declaración de dos la única forma de hacerlo?

+3

¿Por qué crees que necesitas un puntero a un puntero, en este caso? – SingleNegationElimination

+0

posible duplicado de [¿Cómo funciona el puntero a los punteros en C?] (Http://stackoverflow.com/questions/897366/how-do-pointer-to-pointers-work-in-c) –

+1

@Jens Gustedt, esto no es un duplicado La pregunta relacionada pregunta sobre punteros en general. Esta pregunta es sobre un caso específico. –

Respuesta

12

si quieres un puntero a un puntero, el puntero que desea apuntar a debe estar ubicado en algún lugar de la memoria, por lo que parece que no puede haber una "solución de paso" porque necesita una variable de puntero a la que pueda apuntar.

(Nota: Esta frase no está destinado a ser una prueba lingüística para usar "punto" tan a menudo como sea posible en una frase :-))

14

No se puede obtener el puntero a un temporal. &a da como resultado un valor r. Está permitido no tener una dirección real.

+1

Esto es 100% correcto, pero acepté la respuesta de Philip porque entra en la lógica de por qué es eso, en lugar de solo señalar el estándar. –

2

¿Desea un puntero (llámelo PP) a un puntero (llámelo P)?

Entonces P realmente debe existir. Lo que significa que debes declararlo.

Por supuesto, el compilador fallará en &&a - porque no puede tomar la dirección de una dirección. Usted puede tomar la dirección de un puntero, pero primero tendrá que declarar el puntero.

Por lo tanto:

int a = 1; 
int *P = &a; 
int **PP = &P; 
+1

El analizador falla en '&& a' no porque no puede tomar la dirección de una dirección sino porque' && 'es un token único que no es válido en este punto de la declaración. 'int ** ppa = x &&a;' podría ser una inicialización válida para un 'x' adecuadamente tipado y un' y& 'adecuadamente sobrecargado (¡malvado!) pero no sería la dirección de una dirección. –

0

Al hacer lo siguiente:

char a; 
char* b = &a; 
char** c = &b; 

Primero que nada, ahora existe en la pila. Obviamente tiene una dirección de memoria (es decir, su posición de pila) esto es lo que asigna a b. b ahora también existe en la pila y puede pasar su dirección de memoria a c. Sin embargo, no puede tomar la dirección de la dirección de un valor sin la pila intermedia, ya que no existe sin crearla primero.

-1

esto podría funcionar:

int ** ppa = & (int *) {& a};

+0

Hmm, no, no, crea un – fileoffset

7

Los otros muchos tienen razón: su puntero a un puntero debe apuntar a algo. Sin embargo, en C99 se puede engañar mediante el uso de compound literals:

int a = 1; 
int **ppa = &(int *){ &a }; 

literales compuestos son básicamente objetos no identificados y tienen las mismas reglas de almacenamiento como objetos normales. (Pero no puede dar un alcance de función compuesto literal duración de almacenamiento estático con la palabra clave static). Incluso se puede anidar para que pueda reescribir el ejemplo anterior para una sola línea:

int **ppa = &(int *) { &(int) { 1 } }; 
+0

temporal. Es muy probable que este comportamiento no esté definido y probablemente bloquee la aplicación en el primer uso del puntero. El compuesto literal es temporal y el compilador puede reutilizar ese espacio, por lo que '* ppa' apunta a' & a' durante la ejecución de la segunda línea, pero puede apuntar a cualquier otra cosa después. –

+1

@David Rodriguez: No, estás equivocado. El compuesto literal tendrá la misma duración de almacenamiento que 'a' y' ppa': estático cuando está fuera de una función, de lo contrario será automático durante el resto del bloque de cierre. Ver C99 6.5.2.5 (6). – schot

+1

Tiene toda la razón. Debería haber verificado el estándar antes de saltar a un comentario ... Si en algún punto modificas la respuesta, comenta y convertiré el -1 en un +1, no me permite cambiarlo ahora. En cualquier caso, dependiendo de lo que quiera hacer con el puntero, es * tan peligroso * como la solución de variable intermedia. –

5

C++ 03 [Section 5.3.1] dice

El resultado de la & operador unitario es un puntero a su operando. El operando debe ser lvalue o una identificación calificada.En el primer caso, si el tipo de la expresión es “T”, el tipo del resultado es “puntero a T.”

En &&a, & operador no se puede aplicar al resultado de &a porque el resultado no es un lvalue.

Lea también this hilo

2

Una dirección es un número. Solo tiene una dirección propia si se mantiene en una variable, es decir, un puntero. Así

int *i1 = &a; 

tiene sentido, pero

int **i2 = &&a; 

no tiene sentido. Sin embargo,

int **i2 = &i1; 

tiene sentido. ¿Tener sentido?

+1

Su terminología es incorrecta. El operador de dirección * * produce un puntero, consulte [ISO03, 5.3.1 expr.unary.op §2]. Es común llamar puntero * valores * "direcciones", y puntero * variables * "punteros", pero estrictamente hablando, eso es incorrecto. – fredoverflow

+0

La terminología que utilicé es de uso común. El valor de un puntero en el sentido del Estándar es una dirección en cualquier sentido, que a su vez es un número en cualquier sentido. Para poner lo que dije de otra manera, y no arroja una * variable, * por lo que no arroja nada cuya dirección se puede tomar. – EJP

0

El problema cuando haces algo como &&a; es que estás pidiendo "la dirección de la dirección de a".

Eso no tiene sentido. Podemos obtener la dirección de a bien, pero eso no nos da una variable que podemos tomar la dirección de. Simplemente nos da un valor de puntero. Hasta que ese valor esté almacenado en algún lugar, no podemos tomar sus direcciones.

Si tiene un código como 2+2, el resultado tampoco tiene una dirección. Es solo el valor 4, pero aún no se ha almacenado en ninguna parte, por lo que no podemos tomar una dirección. Una vez que lo almacenamos en una variable int, podemos tomar la dirección de esa variable.

Básicamente, el problema es la diferencia entre valores y variables. Un valor es solo un número (o un carácter, o algún otro dato). Una variable es un lugar en la memoria donde se almacena un valor. Una variable tiene una dirección, pero un valor no.

En C++ - speak, es la diferencia entre rvalues ​​y lvalues. Un rvalue es esencialmente temporal, generalmente es un valor que se devolvió de otra operación (como el operador & en su caso), pero que aún no se ha almacenado en ningún lugar.

Una vez que lo almacena en una variable, obtiene un valor l, y lvalues ​​tiene una dirección que puede tomar.

Así que sí, necesita las dos declaraciones por separado. Primero tomas la dirección y luego almacenas esa dirección en alguna parte. Y luego puedes tomar la dirección de este "en algún lugar".

+0

Su terminología es incorrecta. El operador de dirección * * produce un puntero, consulte [ISO03, 5.3.1 expr.unary.op §2]. Es común llamar puntero * valores * "direcciones", y puntero * variables * "punteros", pero estrictamente hablando, eso es incorrecto. – fredoverflow

+0

@Fred: suficiente. Sospeché que me metería en problemas por eso. ;) Eso me enseñará a tratar de reformular la semántica de C++: p – jalf

+0

Se corrigió un poco. Espero que tenga los bits más engañosos. – jalf