Esta estructura
char **Data[70]={NULL};
es una matriz de 70 punteros a punteros a char. El compilador asigna 70 * sizeof(char**)
bytes para esta matriz, que suponiendo punteros de 32 bits es de 280 bytes.
Si piensa internamente en un "puntero a char" como una cadena, que no es cierto pero está lo suficientemente cerca, esta es una matriz de 70 punteros a cadenas. Para hacer un poco de arte ASCII y pretender que ha asignado y lleno de algunos valores ....
Array of One or more
char ** char *
+---------+ +---------+
| 0 | --> | ptr | --> "Hello, world"
+---------+ +---------+
| 1 |
+---------+ +---------+
| 2 | ----> | ptr2 | --> "Goodbye, cruel world"
+---------+ +---------+
| 3 |
+---------+ +---------+
| 4 | ------> | ptr3[0] | --> "Message 0"
+---------+ +---------+
... | ptr3[1] | --> "Message 1"
+---------+ +---------+
| 69 | | ptr3[2] | --> "Message 2"
+---------+ +---------+
que podría hacer lo anterior con código como este (comprobación de valores de retorno de error malloc omitidos):
char **Data[70]={NULL};
char **ptr, **ptr2, **ptr3;
ptr = (char **) malloc(sizeof(char *));
*ptr = "Hello, world";
Data[0] = ptr;
ptr2 = (char **) malloc(sizeof(char *));
*ptr2 = "Goodbye, cruel world";
Data[2] = ptr2;
ptr3 = (char **) malloc(10 * sizeof(char *));
Data[4] = ptr3;
ptr3[0] = "Message 0";
ptr3[1] = "Message 1";
...
ptr3[9] = "Message 9";
printf("%s\n", *Data[0]);
printf("%s\n", Data[2][0]);
printf("%s\n", Data[4][0]);
printf("%s\n", Data[4][1]);
...
printf("%s\n", Data[4][9]);
Piénselo de esta manera: cada entrada en la matriz es char **
. Cada entrada puede apuntar a una ubicación arbitraria en la memoria, siendo dicha ubicación char *
y así poder apuntar a una matriz de caracteres terminada en nulo, también conocida como "cadena".
Nota cuidadosamente la distinción entre esto y lo que se obtiene cuando se asigna una matriz 2D:
char *Data2[10][70]={NULL};
La asignación de Data2
anterior le da una matriz de 2 dimensiones de char *
punteros, siendo dicha 2-d matriz asignado en un solo trozo de memoria (10 * 70 * sizeof(char*)
bytes, o 2800 bytes con punteros de 32 bits). No tiene la capacidad de asignar los punteros char **
a ubicaciones arbitrarias en la memoria que tenga con la matriz unidimensional de char **
punteros.
También tenga en cuenta (dada anteriormente declaraciones de Data
y Data2
) que el compilador generará código diferente para las siguientes referencias array:
Data[0][0]
Data2[0][0]
Aquí hay otra manera de pensar acerca de esta: Imagine que tiene varias arrays de punteros a cadenas:
char *table0[] = { "Tree", "Bench", "Stream" };
char *table1[] = { "Cow", "Dog", "Cat" };
char *table2[] = { "Banana", "Carrot", "Broccoli" };
char **Data[3];
Data[0] = table0;
Data[1] = table1;
Data[2] = table2;
tiene una matriz de punteros a "conjunto de puntero a char". Si ahora imprime el valor de data[1][1]
, piénselo de esta manera: le muestra un puntero al arreglo table1
. Entonces el valor table1[1]
es igual a "Dog"
.
su gran respuesta ha sido desvergonzadamente vinculada a esta pet-peeve-answer: http://stackoverflow.com/questions/423823/whats-your-favorite-programmer-ignorance-pet-peeve/484900#484900. aplausos :) –
gracias por tomarse el tiempo para escribir una buena respuesta. Eso aclara mucho. En cuanto a su primer diagrama, ¿cómo sabe si el puntero apunta a un solo puntero (como ptr2) o una matriz de punteros, como ptr3 [0-2] ¿Puede ser ambos como en el diagrama? Por ejemplo, tu segundo diagrama es consistente. Gracias. –
No hay forma de saber a qué apunta exactamente un puntero char **. Podría apuntar a un área de memoria de cualquier tamaño. Sin mirar el código donde está asignado, no hay forma de saberlo. – Eddie