简体   繁体   English

指针数组如何工作?

[英]How does an array of pointers to pointers work?

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

What is the correct terminology for this? 这个术语的正确用法是什么? How else could it be written? 怎么写呢? What does it look like in memory? 它在记忆中看起来像什么? I am reading many tutorials on pointers but I don't see it in this syntax. 我正在阅读许多关于指针的教程,但我没有在这种语法中看到它。 Any help is appreciated. 任何帮助表示赞赏。 Thanks. 谢谢。

This structure 这种结构

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

is an array of 70 pointers to pointers to char. 是指向char的指针的70个指针的数组。 The compiler allocates 70 * sizeof(char**) bytes for this array, which assuming 32-bit pointers is 280 bytes. 编译器为此数组分配70 * sizeof(char**)字节,假设32位指针为280字节。

If you internally think of a "pointer to char" as a string, which isn't true but it's close enough, then this is an array of 70 pointers to strings. 如果你在内部将“指向char的指针”视为一个字符串,这不是真的但它足够接近,那么这是一个包含70个字符串指针的数组。 To make some ASCII art and pretend that you have allocated and filled some values.... 制作一些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"
+---------+         +---------+

You could do the above with code like this (error checking malloc return values skipped): 您可以使用这样的代码执行上述操作(错误检查跳过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]);

Think of it this way: Each entry in the array is a char ** . 可以这样想:数组中的每个条目都是char ** Each entry can point to an arbitrary location in memory, said location(s) being char * and thus being able to point to a null-terminated character array aka "string." 每个条目可以指向存储器中的任意位置,所述位置是char * ,因此能够指向以空字符结尾的字符数组,即“字符串”。

Note carefully the distinction between this and what you get when you allocate a 2D array: 请仔细注意这与您分配2D数组时所获得的区别:

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

The allocation of Data2 above gives you a 2-dimensional array of char * pointers, said 2-d array being allocated in a single chunk of memory ( 10 * 70 * sizeof(char*) bytes, or 2800 bytes with 32-bit pointers). 上面的Data2分配给你一个char *指针的二维数组,表示2-d数组被分配在一块内存中( 10 * 70 * sizeof(char*)字节,或2800字节,32位指针) )。 You don't have the ability to assign the char ** pointers to arbitrary locations in memory that you have with the single-dimensional array of char ** pointers. 您无法将char **指针分配给内存中与char **指针的一维数组一起使用的任意位置。

Also note (given above declarations of Data and Data2 ) that the compiler will generate different code for the following array references: 另请注意(在上面的DataData2声明中)编译器将为以下数组引用生成不同的代码:

Data[0][0]
Data2[0][0]

Here's another way to think about this : Imagine that you have several arrays of pointers to strings: 这是考虑这个问题的另一种方法 :想象一下,你有几个指向字符串的指针数组:

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;

You have an array of pointers to "array of pointer to char". 你有一个指向“char指针数组”的指针数组。 If you now print the value of data[1][1] , think of it like this: data[1] gets you a pointer to the array table1 . 如果你现在打印data[1][1] ,可以这样想: data[1]给你一个指向数组table1的指针。 Then the value table1[1] equals "Dog" . 然后值table1[1]等于"Dog"

It's slightly tricky to think of a practical use for an array of char**. 想到一个char **数组的实际用途有点棘手。 Especially one with 70 elements. 特别是70个元素。

However, suppose that I'm going to run 70 programs. 但是,假设我要运行70个程序。 As you probably know, program arguments are commonly passed as a char** argv parameter to main() (or char*[] argv , which in a function signature is the same thing). 您可能知道,程序参数通常作为char** argv参数传递给main() (或char*[] argv ,它在函数签名中是相同的东西)。 So if I wanted to store the argv pointers for all those programs, I'd used an array just like Data . 因此,如果我想为所有这些程序存储argv指针,我就像Data一样使用数组。 Obviously I'd also need some more memory elsewhere, for the actual strings and argv arrays to occupy, but it's a start. 显然,我在其他地方也需要更多的内存,因为实际的字符串和argv数组占用了,但它是一个开始。

Initializing an array with {NULL} sets all its elements to NULL. 使用{NULL}初始化数组{NULL}其所有元素设置为NULL。 This is a useful shorthand: you can initialize an array with {firstelement, secondelement, ...} , but if you don't provide enough terms, all the rest are treated as 0. 这是一个有用的简写:您可以使用{firstelement, secondelement, ...}初始化数组,但如果您没有提供足够的术语,则所有其余的都被视为0。

Just like any other array of pointers, initialized with {NULL}, what this looks like in memory is 70 NULL pointers sitting in a row. 就像使用{NULL}初始化的任何其他指针数组一样,在内存中看起来像70个空指针就在一行中。 There's (usually) no difference in memory between a char** and any other object pointer. char**和任何其他对象指针之间的内存(通常)没有区别。 I think it is legal to write a weird implementation in which there is a difference, but don't hold your breath waiting to come across one. 我认为编写一个奇怪的实现是有道理的,但有一点不同,但是不要屏住呼吸等待。

So, the difference between 70 NULL char** in a row and 70 NULL char* in a row is what would be on the other end of the pointer, if they weren't NULL. 因此,如果它们不是NULL,则行中70 NULL char**和行中70 NULL char*之间的差异在指针的另一端。 On the other end of a char** is a pointer to a char. char**的另一端是一个指向char的指针。 On the other end of a char* is a char. char*的另一端是char。 Either the pointer, or the char, might be the first in an array, depending on how it's being used. 指针或char可能是数组中的第一个,具体取决于它的使用方式。

This isn't very obvious: 这不是很明显:

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

but with an alternative declaration, like: 但有一个替代声明,如:

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

we can easily see that it's a 2 dimensional array of strings. 我们可以很容易地看到它是一个二维的字符串数组。

Edit: I used Data[2][3] to show that it's a 2D array. 编辑:我使用Data [2] [3]来表明它是一个2D数组。 I used fixed size for the dimensions like 2 & 3 just for demonstration. 我使用固定尺寸的尺寸如2和3只是为了演示。 Of course we can have: 当然我们可以:

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

or char** Data[] 或者char** Data[]

Ok, here is what I mean by 2-D array: 好的,这就是二维数组的意思:

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]);
}

What you've got is an array of 70 pointers, each of which points to another pointer, each of those pointers point to a char. 你得到的是一个包含70个指针的数组,每个指针指向另一个指针,每个指针都指向一个char。 On an interesting note, arrays themselves are pointers so you have three levels of pointers. 有趣的是,数组本身就是指针,所以你有三个指针级别。

This is, effectively, a pointer to a pointer to pointers. 实际上,这是指向指针指针的指针。 However, since a "pointer" is nothing but a location in memory, there really isn't much use in doing this over just doing char* Data[70], other than making it obvious that each char* is a pointer to another char*, instead of a pointer to char. 但是,由于“指针”只不过是内存中的一个位置,因此除了明确表示每个char *是指向另一个char的指针之外,实际上没有多少用于执行char * Data [70]。 *,而不是指向char的指针。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM