Эта структура
char **Data[70]={NULL};
- это массив из 70 указателей на указатели на символ. Компилятор выделяет 70 * sizeof(char**)
байтов для этого массива, что предполагает, что 32-битные указатели равны 280 байтов.
Если вы внутренне думаете о «указателе на символ» как о строке, которая не соответствует действительности, но достаточно близка, то это массив из 70 указателей на строки. Чтобы создать ASCII-арт и сделать вид, что вы выделили и заполнили некоторые значения ....
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"
+---------+ +---------+
Вы могли бы сделать вышеупомянутое с кодом, подобным этому (ошибка проверки возвращаемых значений malloc пропущена):
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]);
Подумайте об этом так: каждая запись в массиве - это char **
. Каждая запись может указывать на произвольное местоположение в памяти, причем указанное местоположение (я) равно char *
и, следовательно, может указывать на массив символов с нулевым символом в конце, называемый «строка».
Обратите внимание на разницу между этим и тем, что вы получаете, когда выделяете двумерный массив:
char *Data2[10][70]={NULL};
Выделение Data2
, приведенное выше, дает вам двумерный массив указателей char *
, причем указанный двумерный массив размещается в одном фрагменте памяти (10 * 70 * sizeof(char*)
байт, или 2800 байт с 32-разрядными указателями). ). У вас нет возможности назначать указатели char **
произвольным местам в памяти, которые у вас есть с одномерным массивом указателей char **
.
Также обратите внимание (с учетом приведенных выше объявлений Data
и Data2
), что компилятор сгенерирует другой код для следующих ссылок на массив:
Data[0][0]
Data2[0][0]
Вот еще один способ подумать об этом : представьте, что у вас есть несколько массивов указателей на строки:
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;
У вас есть массив указателей на «массив указателей на символ». Если вы теперь выводите значение data[1][1]
, подумайте об этом так: data[1]
возвращает указатель на массив table1
. Тогда значение table1[1]
равно "Dog"
.