指针数组如何工作?

时间:2009-06-19 01:02:59

标签: c arrays pointers

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

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

5 个答案:

答案 0 :(得分:24)

这个结构

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 *,因此能够指向以空字符结尾的字符数组,即“字符串”。

请仔细注意这与您分配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"

答案 1 :(得分:2)

考虑一组char **的实际用途有点棘手。特别是70个元素。

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

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

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

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

答案 2 :(得分:1)

这不是很明显:

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

但有另一个声明,例如:

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

我们可以很容易地看到它是一个二维的字符串数组
修改    我使用Data [2] [3]来表明它是一个2D数组。我使用 fixed 尺寸来获得像2& 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]);
}

答案 3 :(得分:1)

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

答案 4 :(得分:0)

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