指针数组如何工作?

char **Data[70]={NULL}; 

这个术语的正确用法是什么? 怎么还能写呢? 它在记忆中看起来像什么? 我正在阅读有关指针的许多教程,但我没有在这种语法中看到它。 任何帮助表示赞赏。 谢谢。

这种结构

 char **Data[70]={NULL}; 

是指向char的指针的70个指针的数组。 编译器为此数组分配70 * sizeof(char**)字节,假设32位指针为280字节。

如果你在内部将“指向char的指针”视为一个字符串,这不是真的,但它足够接近,那么这是一个包含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 * ,因此能够指向以null结尾的字符数组,即“字符串”。

请仔细注意这与您分配2D数组时所获得的区别:

 char *Data2[10][70]={NULL}; 

上面的Data2分配给你一个char *指针的二维数组,表示2-d数组被分配在一块内存中( 10 * 70 * sizeof(char*)字节,或2800字节,32位指针) )。 您无法将char **指针分配给内存中使用char **指针的一维数组的任意位置。

另请注意(在上面的DataData2声明中)编译器将为以下数组引用生成不同的代码:

 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; 

你有一个指向“char指针数组”的指针数组。 如果你现在打印data[1][1] ,可以这样想: data[1]你提供一个指向数组table1的指针。 然后值table1[1]等于"Dog"

想到char **数组的实际用法有点棘手。 特别是70个元素。

但是,假设我要运行70个程序。 您可能知道,程序参数通常作为char** argv参数传递给main() (或char*[] argv ,它在函数签名中是相同的东西)。 因此,如果我想为所有这些程序存储argv指针,我就像Data一样使用数组。 显然,我在其他地方也需要更多的内存,因为实际的字符串和argv数组占用了,但它是一个开始。

使用{NULL}初始化数组{NULL}其所有元素设置为NULL。 这是一个有用的简写:您可以使用{firstelement, secondelement, ...}初始化数组,但如果您没有提供足够的术语,则所有其余的都被视为0。

就像使用{NULL}初始化的任何其他指针数组一样,在内存中看起来像是70个NULL指针。 char**和任何其他对象指针之间的内存(通常)没有区别。 我认为写一个奇怪的实现是有道理的,但有一点不同,但是不要屏住呼吸等待。

因此,如果它们不是NULL,则行中70 NULL char**和行中70 NULL char*之间的差异是指针另一端的差异。 在char**的另一端是一个指向char的指针。 在char*的另一端是char。 指针或char可能是数组中的第一个,具体取决于它的使用方式。

你得到的是一个包含70个指针的数组,每个指针指向另一个指针,每个指针都指向一个char。 有趣的是,数组本身就是指针,所以你有三个指针级别。

这不是很明显:

 char **Data[70]={NULL}; 

但有一个替代声明,如:

 char* Data[2][3] = { {"Nick", "Tom", "Helen"}, {"one", "two", "three"} }; 

我们可以很容易地看到它是一个二维的字符串数组。

编辑:我使用Data [2] [3]来表明它是一个2D数组。 我使用固定尺寸的尺寸如2和3只是为了演示。 我们当然可以:

 char* Data[][3]={ {"Nick", "Tom", "Helen"}, {"one", "two", "three"}, // ... }; 

char** Data[]

好的,这就是二维数组的意思:

 char** Data[2]={0}; void test() { char* d1[] = {"1", "2"}; char* d2[] = {"10", "20", "30"}; Data[0] = d1; Data[1] = d2; printf("%s\n", Data[0][0]); printf("%s\n", Data[0][1]); printf("%s\n", Data[1][0]); printf("%s\n", Data[1][1]); printf("%s\n", Data[1][2]); } 

实际上,这是指向指针指针的指针。 但是,由于“指针”只不过是内存中的一个位置,因此除了明确每个char *是指向另一个char的指针之外,实际上没有多少用于执行char * Data [70]。 *,而不是指向char的指针。