En C, un puntero al tipo T
apunta a una ubicación donde se almacenan algunos datos del tipo T
. Para mantener las cosas concretas, voy a hablar sobre T = int
a continuación.
El uso más simple de un puntero podría ser la de apuntar a un valor:
int a = 42;
int *pa = &a;
Ahora, *pa
y a
son ambos el mismo, e igual a 42
. Además, *pa
y pa[0]
son tanto equivalentes: así, por ejemplo, se puede hacer:
*pa += 1; /* a is 43 */
pa[0] += 1; /* a is 44 */
a += 1; /* a is 45 */
De hecho, el compilador de C se traduce pa[0]
a *(pa+0)
automáticamente.
Un puntero puede apuntar a un lugar que se encuentra dentro de una secuencia de datos:
int arr[] = { 1, 2, 3 }; /* 3 ints */
int *parr = arr; /* points to 1 */
Ahora, nuestra memoria es el siguiente:
+---+---+---+
arr: | 1 | 2 | 3 |
+---+---+---+
+------+ |
| parr | ----+
+------+
parr
es un puntero que apunta a la primera elemento de arr
en la imagen de arriba. Por cierto, parr
también tiene una caja alrededor, porque tenemos que almacenar el objeto parr
en algún lugar de la memoria. El valor de parr
es la dirección del primer elemento de arr
.
Ahora, podemos usar parr
acceder a los elementos de arr
:
arr[0] == parr[0]; /* true */
parr[1]++; /* make arr[1] equal to 3 */
Por lo tanto, el puntero puede ser utilizado para significar "señalo a la primera de n elementos en una tienda contigua de algunos objetos" . Por supuesto, uno tiene que saber cuántos objetos hay para que funcione este esquema: pero una vez que lo recordamos, es una forma extremadamente conveniente de acceder a la memoria en C.
Se puede hacer que el puntero apunte dinámicamente asignado la memoria, así:
#include <stdlib.h>
size_t n;
/* now, obtain a value in n at runtime */
int *p = malloc(n * sizeof *p);
Si la llamada tiene éxito malloc()
anterior, p
ahora apunta a la primera de un área contigua asignado durante 10 s int
. Podemos usar p[0]
a través de p[n-1]
en nuestro programa ahora.
Probablemente conozca la mayoría o la totalidad de las anteriores :-), pero aun así, lo anterior ayuda a comprender lo que voy a decir a continuación.
¿Recuerda que dijimos que un puntero puede apuntar a una secuencia contigua de objetos del mismo tipo? El "mismo tipo" puede ser otro tipo de puntero también.
#include <stdlib.h>
int **pp;
pp = malloc(3 * sizeof *pp);
Ahora, pp
apunta a un int *
. Volviendo a nuestra imagen anterior:
+------+------+------+
| | | |
+------+------+------+
+------+ |
| pp | ----+
+------+
Y cada una de las 3 cajas es una int *
, que puede señalar al primer elemento de una secuencia contigua de int
s:
for (i=0; i < 3; ++i)
pp[i] = malloc((i + 1) * sizeof *ppi[i]);
Aquí, asignamos espacio para un int en pp[0]
, 2 en pp[1]
, y 3 en pp[3]
:
+------+ +---+
pp -------->| |-------->| |
+------+ +---+---+
| |-------->| | |
+------+ +---+---+---+
| |-------->| | | |
+------+ +---+---+---+
Así, pp[0]
es un puntero a uno int
, y int
es el único int
en un bloque dinámicamente asignado de int
s. En otras palabras, pp[0][0]
es int
, y apunta a la casilla superior "ancho-3" arriba. Del mismo modo, pp[1][0]
y pp[1][1]
son ambos válidos y son los dos cuadros debajo del cuadro pp[0][0]
.
El uso más común de puntero a puntero es crear una "matriz" de 2 dimensiones en tiempo de ejecución:
int **data;
size_t i;
data = malloc(n * sizeof *data);
for (i=0; i < n; ++i)
data[i] = malloc(m * sizeof *data[i]);
Ahora, suponiendo que todas malloc()
s éxito, data[0]
... data[n-1]
son válidos los valores int *
, cada uno apunta a una longitud separada m
objetos contiguos int
.
Pero, como mostré anteriormente, un puntero al puntero no necesita tener el mismo "número de elementos" en cada una de sus "filas". El ejemplo más obvio es argv
in main()
.
Por ahora, como se puede adivinar, un puntero "3 niveles de profundidad", como int ***p;
está bien y puede ser útil en C.
Sí lo haría, 3 matrices de dimensión es donde empieza a obtener una Un poco complicado, después de las matrices de 3 dimensiones mi cabeza empieza a doler y trato de encontrar otra forma de almacenar mis datos. – Craig
Una matriz de 3 dimensiones es como almacenar información en una caja compartimentada, por lo que si tiene una caja de 10x10x10, y cada 1x1x1 almacena una información, puede almacenar 1000 piezas de información. Pero como dije después de tres punteros, es posible que desee ver otra forma de almacenar los datos. Un ejemplo de uso de matriz 3D sería una imagen, digamos un mapa de bits de 1024x1024, y en cada uno de los píxeles en la imagen que desee almacenar un valor R, G, B podría tener una matriz de 1024x1024x3, lo que significa que posición en la cuadrícula 1024x1024 puede almacenar [0] [1] y [2] cantidad de datos. – Craig