1

Hoy he aprendido lo que son los punteros y tras estar un rato probando programas, me ha surgido una duda. Los punteros devuelven direcciones de memoria, igual que el operador &.

Entonces:

¿Qué diferencia hay entre estos dos programas?:

int a = 15;
int *ptr = &a;
printf("%x",*ptr);

Y

int a = 15;
printf("%x",&a);

Muchas gracias y saludos

ByRuss X
  • 451
  • 2
  • 14

2 Answers2

4

Tus dos ejemplos no son equivalentes.

a es una variable que contiene un entero (el valor 15 en tu caso). Ese 15 estará almacenado en algún lugar de la memoria. &a te dice precisamente en qué dirección está almacenado el 15.

ptr es otra variable que en lugar de contener un entero, contiene direcciones de memoria (que en el fondo son números también, pero tienen otro significado). En tu caso contiene la dirección de la variable a. Imagina que esta dirección es la 0x12345678. Pues bien, el valor de ptr sería 0x12345678, y en la dirección 0x12345678 hay un 15.

ptr, al ser una variable, estará a su vez en otra dirección que podrías averiguar con &ptr. Digamos que esa dirección es 0x55555555. Pues bien, en la dirección 0x55555555 habría el valor 0x12345678.

Ejemplo

Si imprimieras ptr, verías el 0x12345678. Sin embargo al usar la sintaxis *ptr lo que haces es desreferenciar el puntero, es decir, en lugar de acceder a lo que hay en ptr, accedes a lo que hay en la dirección apuntada por ptr, en este caso el 15.

Por tanto tu línea:

printf("%x",*ptr);

Mostraría el 15 (en hexadecimal debido al %x). Si lo que querías era ver el 0x12345678 tendrías que haber escrito sin el asterisco.

printf("%x",ptr);

Y si quisieras ver la dirección en la que está almacenado el propio puntero (0x55555555 según mi ejemplo) pondrías:

printf("%x", &p);

Tu segundo programa, que pone:

printf("%x",&a);

mostrará la dirección de a, que sería lo mismo que poner ptr (sin asterisco ni &).

Analogía. La memoria es como una taquilla con cajones numerados. Puedes poner objetos dentro y para acceder a ellos necesitas conocer bien el nombre del cajón (a) o bien su número (&a). Un puntero es un cajón que contiene un papelito con el número de otro cajón. El operador & te permite obtener el número de un cajón dado (&a sería el número del cajón llamado a, &p sería el número del cajón llamado p). El operador * te permite acceder a un cajón conocido su número. *p es "el valor contenido en el cajón cuyo número está en el cajón llamado p".

abulafia
  • 53,696
  • 3
  • 45
  • 80
  • Tienes toda la razón, mis disculpas. – FranAcuna Oct 09 '20 at 23:11
  • Entonces, si accediesemos a `a` como si fuese un puntero, ¿obtendriamos el valor que está guardado en `a` (en este caso `15`) y podriamos acceder a la dirección de memoria de ese valor? – ByRuss X Oct 10 '20 at 13:57
  • @ByRussX Veo que este tema te ha interesado, pues has planteado [aqui](https://es.stackoverflow.com/questions/396093/se-puede-acceder-a-cualquier-valor-como-si-fuese-un-puntero) esa misma pregunta. Allí te doy una respuesta más detallada. – abulafia Oct 10 '20 at 14:51
  • Si, lo he visto, muchas gracias, pero me da un error de compilación :( – ByRuss X Oct 10 '20 at 15:05
2

¿Qué diferencia hay entre usar un puntero y usar &?

El operador & devuelve la dirección de memoria de una variable (e incluso la de un puntero).

Un puntero simplemente es una variable que guarda la dirección de memoria de otra variable. El objetivo principal de los punteros es leer o escribir en memoria.

¿Qué diferencia hay entre estos dos programas?

int a = 15;
int *ptr = &a;
printf("%x",*ptr);

Y

int a = 15;
printf("%x",&a);

En el primer código, estás guardando la dirección de memoria de a en el puntero ptr y luego desreferencia el puntero para imprimir el contenido de la variable a.

En el segundo código, en cambio, estás usando el operador ampersand para imprimir directamente la dirección de memoria de a.

¿para que sirven los punteros, si podemos usar &?

En el ejemplo propuesto anteriormente no se ve la utilidad de los punteros pero si necesitaras modificar (o leer) el contenido de una variable durante la ejecución de una función, si sería útil.

Ejemplo:

void foo(int* x)
{
    *v = 10;
}

int main(void)
{
    int x = 1;
    foo(&x);
    printf("%d", x);
    return 0;
}

De este modo, se emula el pase por referencia, aunque en C se lo suele llamar pase por puntero.

Un ejemplo clarísimo, es la funcion strlen, en la cual, devuelve la longitud de una cadena. Como verás, esta rutina tiene como parámetro, un puntero a char, a partir de este puntero, es como puede leer el contenido del array (durante la ejecución de la función) y gracias a ello, puede retornar dicha longitud.

Otra utilidad de los punteros es cuando quieres crear un array dinámico. Para esto debes usar la función malloc (para reservar memoria) y sí o sí, debes usar punteros.

Ejemplo:

int main(void)
{
    int n;
    int* p;
    printf("Ingrese la longitud del vector");
    scanf("%d", &n);
    p = malloc(n * sizeof(int)); //Crea un array de enteros de N elementos..
    //more code..
    return 0;
}

Con los punteros de C puedes hacer muchas cosas, sobretodo cuando inicias en estructura de datos (por ejemplo, tendrás que usar punteros para crear una lista enlazada).

Fuente:

Applications of Pointers

MrDave1999
  • 7,491
  • 1
  • 7
  • 22