¿Puede un puntero apuntarse a sí mismo?

9 minutos de lectura

¿Puede un puntero apuntarse a si mismo
láser

Mi pregunta es: Si una variable de puntero tiene la misma dirección que su valor, ¿realmente se está apuntando a sí misma?

Por ejemplo, en el siguiente fragmento de código, es a un puntero a sí mismo?

#include<stdio.h>

int main(){
   int* a;
   int b = (int)&a;
   a = b;
   printf("address of a = %d\n", &a);
   printf("  value of a = %d\n", a);
}

Si a no es un puntero a sí mismo, entonces la misma pregunta se plantea de nuevo: ¿Puede un puntero señalarse a sí mismo?

Además, ¿cómo es útil un puntero autoapuntador?

  • gente, ¿por qué los negvotos? muy facil para ti??

    – Lazer

    28 de marzo de 2010 a las 6:43

  • Mi pregunta es… — una “duda” es algo completamente diferente.

    – Éter

    28 de marzo de 2010 a las 18:07

  • Aunque es legal, me pregunto qué hace realmente el compilador cuando se encuentra con algo como esto. Dado que el compilador realiza alguna optimización propia, apostaría a que la elimina. Pero, no podría decir con certeza.

    – Natalia Adams

    28 de marzo de 2010 a las 20:40

  • Aquí hay un enlace a esta pregunta: stackoverflow.com/questions/2532102/…

    – amdn

    12/03/2015 a las 20:59

  • @amdn Lo que necesita es un puntero a su propio comentario.

    – bombomb007

    1 de marzo de 2018 a las 14:24


void* p = &p;

No es muy útil, pero las estructuras que apuntan a sí mismas son útiles en listas circulares de longitud 1:

typedef struct A {
  struct A* next;
} A;

A a = { &a };

Según su ejemplo exacto, creo que quiso decir:

int* a;
int b = (int)&a;
a = (int*)b;

// which can be simplified to:
int* a = (int*)&a;

  • Tenga en cuenta que lo que hizo con la estructura es diferente de lo que estaba tratando de hacer. Un puntero que se apunta a sí mismo es bastante diferente de una estructura que tiene un puntero a sí mismo. Sin embargo, +1 para el ejemplo, ya que eso es probablemente en lo que debería estar pensando con los punteros autorreferenciales.

    – Phil

    28 de marzo de 2010 a las 6:53

  • @Phil: es conceptualmente diferente, que es de donde proviene todo el beneficio, pero tenga en cuenta que A::next se apunta a sí mismo, ya que es el primer miembro de la estructura, por lo que &a == &a.next.

    Roger Paté

    28 de marzo de 2010 a las 14:44


  • El primer ejemplo es realmente útil: crea un valor de puntero único en tiempo de compilación que podría ser útil para marcar ciertos objetos o transmitir información que no es posible de otro modo en algunas situaciones (por ejemplo, API no modificables). Pero para esa definición del puntero solo sería suficiente … asignarlo solo le ahorra a uno usar & Adicionalmente 🙂

    – stefanct

    9 mayo 2016 a las 23:35

1647562029 512 ¿Puede un puntero apuntarse a si mismo
Leva

Lo que realmente estás haciendo allí es no que el puntero apunte a sí mismo. Eres usando el espacio de memoria asignado para el puntero para almacenar la ubicación del puntero. Un puntero a un int apunta a ints, nunca a otros punteros a ints, incluido él mismo.

Por ejemplo, supongamos que crea un puntero a:

int * a;

Obtiene su propio lugar en la memoria:

   4     a (5)    6
[....][00000000][....]

En este ejemplo simple, digamos que a está en la ubicación de memoria ‘5’.

Si hicieras esto:

a = (int*)&a;

… ocurriría lo siguiente:

   4     a (5)    6
[....][00000005][....]

Lo que está pasando aquí es que a está apuntando a lo que cree que es un número entero en la ubicación 5. Esta también es la misma ubicación de memoria que &a está señalando, pero en el contexto de lo que a está apuntando, ahora está apuntando al número entero en la ubicación 5, y ese número entero es 5.

Por ejemplo, ambos funcionarían:

cout<<(int)a;//outputs 5
cout<<*a;//Outputs the integer at memory location 5 - which is 5.

Si quisiera crear un puntero a a, definitivamente podría hacerlo, de cualquiera de estas formas:

int **b = (int**)a;

o

int ** b = &a;

Pero es muy importante darse cuenta de que a no es un puntero a sí mismo. Es un puntero a la entero en la ubicación que almacena – que resulta ser lo mismo que su propia ubicación.


Para mostrar más (a través de un ejemplo aún más simple) lo que está pasando, algo similar podría pasar con un int. Es decir, puede almacenar la ubicación de memoria de un int dentro de sí mismo:

int a=999;

a ahora tiene una ubicación en la memoria y tiene un valor de 999 (supondremos que se colocó en la ubicación de memoria ’46’):

  45     a (46)   47
[....][00000999][....]

Está en la ubicación ’46’; si quisiéramos, podríamos almacenar este número como un número entero dentro a:

a=(int)&a;

  45     a (46)   47
[....][00000046][....]

y ahora a es igual a &a en valor, pero no en tipoa es solo un número entero, no apunta a sí mismo mágicamente ahora solo porque lo usamos para almacenar su propia ubicación de memoria.

  • No entiendo por qué, en el primer ejemplo, a no se apunta a sí mismo, ya que su contenido es una dirección de memoria (definición de puntero, ¿no?) -en este caso, su propia dirección- y no un número entero (ha sido casteado a un int*). Entonces, obviamente, &a y a producir el mismo resultado cuando se imprima, digamos 0xABCD. Pero ahora, puedo escribir legalmente *a = 0x1234y cout << a muestra que el puntero desreferenciado, a ha sido modificado : &a = 0xABCD pero a = 0x1234. ¿Me equivoco en alguna parte?

    – Greg82

    29 de agosto de 2014 a las 12:08


  • @ Greg82 Porque por definición de int *a;, a debe estar apuntando a un int pero después a=(int*)&a; La variable a estaría apuntando a un int * que no debe hacer. (Para que conste, el tipo de &a es int **) Debido a que los punteros se tratan como números enteros (al menos por lo general y tal vez según lo dictan los estándares de C, no sé), las cosas funcionan, pero no tiene por qué ser el caso en un lenguaje o arquitectura que trata a los punteros de manera diferente a los números enteros.

    – SO apesta

    07/03/2015 a las 21:49


Bueno, primero cambiaría el código:

int **a;
a = (int **)&a;  // otherwise you get a warning, since &a is int ***

No estoy seguro de por qué harías esto, pero está permitido.

printf("The address of a is %p\n", &a);
printf("a holds the address %p\n", a);
printf("The value at %p is %p\n", a, *a); // the *a is why we made a an int **

Deberían imprimir lo mismo.

The address of a is 0x7fffe211d078
a holds the address 0x7fffe211d078
The value at 0x7fffe211d078 is 0x7fffe211d078

Tenga en cuenta que esta no es una buena idea, ya que el primer elenco a = (int **)&a es un hack a la fuerza a mantener un valor que no debería tener. Lo declaras un int ** pero trata de forzar un int *** en ello. Técnicamente, los tamaños son los mismos, pero en general no hagas eso porque la gente espera que un int * contiene la dirección de algo que se puede utilizar como intetc.

Sí y no, porque el tipo de puntero es casi tan importante como el valor del puntero.

Sí, un puntero puede contener la posición de un puntero a sí mismo; incluso un long puede contener la posición de un puntero a sí mismo. (Ints generalmente puede hacerlo, pero no sé si eso está garantizado en todas partes).

Sin embargo, no hay ningún tipo para representar esta relación. Si tiene un puntero que apunta a sí mismo, en realidad tiene un tipo diferente cuando lo elimina. Entonces:

void *p = &p;
// *p is illegal, even though you probably wanted it to equal 'p'
if( *p != p ) {
    printf("Something's wrong");
}

int *i = (int*)&i;
// The following statement is still illegal
if( *i == i ) {
    printf("The universe works!");
}

Diría que la respuesta es ‘no’, porque no funcionará a menos que abuse del sistema de tipos. Creo que es una indicación de que estás haciendo algo mal (aunque a veces es ciertamente necesario).

Desreferenciar un puntero da como resultado un valor de su tipo de valor (por ejemplo, desreferenciar un int* te da un intun int*tipo de valor s). Para que una variable apunte a un puntero, su tipo de valor tendría que ser int*que no es el caso de un int* Como se dijo anteriormente. Entonces, para que un puntero se apunte a sí mismo, tendría que hacer algún tipo de conversión para que el compilador lo obtenga:

int* a;
a = reinterpret_cast<int*>(&a);

desreferenciar aentonces, tendrías un int cuyo valor resulta ser la dirección en la que a se encuentra (truncamiento mod de la dirección para adaptarse al tipo), pero sigue siendo un int y no un int*que requeriría otro elenco.

Un puntero a un puntero a menudo se conoce como un encargarse deque es de un tipo diferente (int**) que un puntero (int*). (Tenga en cuenta que un int** el identificador tiene un tipo de valor int*.)

  • Esta es una respuesta de C++ para una pregunta de C. Por lo demás interesante respuesta.

    – Jared Updike

    14 de febrero de 2012 a las 22:25

Sí, un puntero puede señalarse a sí mismo como se menciona en las respuestas.

Un posible caso de uso es que podemos usar este truco en lugar de punteros NULL. Puede inicializar int * p = (int *)&p, y verificar esto más tarde para ver si el puntero es válido o no. Esto podría haberse usado si, por ejemplo, en un sistema en el que queríamos que 0x0 y todo el rango de direcciones fueran direcciones válidas.

También puede usar este truco en programas especiales de C que no fallarían con el uso del puntero NULL porque los evitaría por completo y el sistema de desreferencia no fallaría. Conducirá a un comportamiento erróneo, pero puede ayudar a la depuración en ciertas situaciones.

  • Esta es una respuesta de C++ para una pregunta de C. Por lo demás interesante respuesta.

    – Jared Updike

    14 de febrero de 2012 a las 22:25

1647562029 207 ¿Puede un puntero apuntarse a si mismo
zaharpopov

Sí, es posible señalarse a sí mismo.

int* a;
a = &a;

Pero no tiene ningún uso, al menos explícitamente así.

  • Lo que trae tipos. &a tiene el tipo int**, asignándolo a a que es un int* es un comportamiento indefinido (bueno, al menos si intenta usar el puntero.

    – nos

    28 de marzo de 2010 a las 18:42

  • error: no se puede convertir ‘int**’ a ‘int*’ en la inicialización

    – Swapnil

    27 de noviembre de 2018 a las 3:45

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad