C语言 双指针 vs 指针数组(**array vs *array[])
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/33746434/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Double pointer vs array of pointers(**array vs *array[])
提问by Maxitj
Im not clearly sure what is the difference between those 2. My professor wrote that **array is same as *array[] and we were presented an example where he used **array (so after classes I tried exchanging that with *array[] and it didn't work), could anyone tell me if those 2 are actually the same as he wrote?? Anyway the class was about dynamic memory allocation
我不太清楚这两个之间有什么区别。我的教授写道 **array 与 *array[] 相同,我们看到了一个他使用 **array 的例子(所以在课后我尝试用 *array[ ] 并且它没有用),谁能告诉我这两个是否真的和他写的一样??无论如何,这门课是关于动态内存分配的
@As soon as I changed the double pointer, this line started throwing error
@一旦我改变了双指针,这一行就开始抛出错误
lines = malloc(sizeof(char*));
and a few others where the memory is beeing reallocated
以及其他一些正在重新分配内存的地方
@2 Hell yeah, here's the whole code
@2 是的,这是整个代码
And for those comments bellow, nope there is nothing inside [] because his statement was
对于下面的那些评论,不,[] 里面没有任何东西,因为他的声明是
**array = *array[]
BIG UPDATE
大更新
I am so sorry for any inconvenience, I was just too tired at the time of writing this post, here is the whole code with no edits
对于给您带来的不便,我深表歉意,写这篇文章的时候我太累了,这里是没有编辑的完整代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **lines; // global text buffer, organized as an array of lines
// --------------------------------------------------------------------------------
// initialize global buffer
void initialize()
{
lines = malloc(sizeof(char*));
lines[0] = NULL;
}
// --------------------------------------------------------------------------------
// return number of lines in buffer
int countLines()
{
int count = 0;
while(lines[count++]) ;
return count-1;
}
// --------------------------------------------------------------------------------
// print one line
void printLine(int line)
{
printf("Line %d: %p %p %s\n",line, &lines[line], lines[line], lines[line]);
}
// --------------------------------------------------------------------------------
// print all lines
void printAll()
{
int num_lines = countLines();
int line = 0;
printf("----- %d line(s) ----\n",num_lines);
while (line < num_lines)
printLine(line++);
printf("---------------------\n");
}
// --------------------------------------------------------------------------------
// free whole buffer
void freeAll()
{
int line = countLines();
while (line >= 0)
free(lines[line--]);
free(lines);
}
// --------------------------------------------------------------------------------
// insert a line before the line specified
void insertLine(int line, char *str)
{
int num_lines = countLines();
// increase lines size by one line pointer:
lines = realloc(lines, (num_lines+2) * sizeof(char*));
// move line pointers backwards:
memmove(&lines[line+1], &lines[line], (num_lines-line+1)*sizeof(char*));
// insert the new line:
lines[line] = malloc(strlen(str)+1);
strcpy(lines[line],str);
}
// --------------------------------------------------------------------------------
// remove the specified line
void removeLine(int line)
{
int num_lines = countLines();
// free the memory used by this line:
free(lines[line]);
// move line pointers forward:
memmove(&lines[line], &lines[line+1], (num_lines-line+1)*sizeof(char*));
// decrease lines size by one line pointer:
lines = realloc(lines, num_lines * sizeof(char*));
}
// --------------------------------------------------------------------------------
// insert a string into specified line at specified column
void insertString(int line, int col, char *str)
{
// make room for the new string:
lines[line] = realloc(lines[line], strlen(lines[line])+strlen(str)+1);
// move characters after col to the end:
memmove(lines[line]+col+strlen(str), lines[line]+col, strlen(lines[line])-col);
// insert string (without terminating 0-byte):
memmove(lines[line]+col, str, strlen(str));
}
// --------------------------------------------------------------------------------
// MAIN program
int main()
{
initialize();
printAll();
insertLine(0,"Das ist");
printAll();
insertLine(1,"Text");
printAll();
insertLine(1,"ein");
printAll();
insertLine(2,"kurzer");
printAll();
printf("lines[2][4] = %c\n",lines[2][4]);
insertString(2,0,"ziemlich ");
printAll();
removeLine(2);
printAll();
freeAll();
return 0;
}
回答by David C. Rankin
If the code you reference in your question was given to you by your professor as an example of the use of pointer arrays of pointers to pointers, I'm not sure how much good that class will actually do. I suspect it was either provided as a debugging exercise or it may have been your attempt at a solution. Regardless, if you simply compile with Warningsenabled, you will find a number of problems that need attention before you advance to debugging your code.
如果您在问题中引用的代码是您的教授提供给您的,作为使用指向指针的指针数组的示例,我不确定该类实际上有多大用处。我怀疑它要么是作为调试练习提供的,要么是您尝试解决的。无论如何,如果您只是在启用警告的情况下进行编译,您会发现在调试代码之前需要注意的许多问题。
Regarding the code you reference, while you are free to use a global text buffer, you are far better served by not using a global buffer and passing a pointer to your data as required. There are some instances, various callback functions, etc. that require global data, but as a rule of thumb, those are the exception and not the rule.
关于您引用的代码,虽然您可以自由使用全局文本缓冲区,但不使用全局缓冲区并根据需要传递指向数据的指针会更好地为您服务。有一些实例、各种回调函数等需要全局数据,但根据经验,这些是例外而不是规则。
Your question basically boils down to "How do I properly use an array of pointers and double-pointers (pointer-to-pointer-to-type) variables. There is no way the topic can be completely covered in one answer because there are far too many situations and contexts where one or the other can be (or should be) used and why. However, a few examples will hopefully help you understand the basic differences.
您的问题基本上归结为“我如何正确使用一组指针和双指针(指针到指针到类型)变量。在一个答案中无法完全涵盖该主题,因为有很远可以(或应该)使用其中一种的情况和上下文以及原因太多了。但是,一些示例有望帮助您理解基本差异。
Starting with the array of pointers to type(e.g. char *array[]). It is generally seen in that form as a function argument. When declared as a variable it is followed with an initialization. e.g.:
从指向类型(例如char *array[])的指针数组开始。它通常以这种形式被视为函数参数。当声明为变量时,它会跟随一个初始化。例如:
char *array[] = { "The quick",
"brown fox",
"jumps over",
"the lazy dog." };
char *array[];by itself as a variable declaration is invalid due to the missing array size between [..]. When used globally, as in your example, the compiler will accept the declaration, but will warnthe declaration is assumed to have one element.
char *array[];由于[..]. 当全局使用时,如在您的示例中,编译器将接受声明,但会警告声明假定具有一个 element。
The elements of arraydeclared above are pointers to type char. Specifically, the elements are pointers to the string-literalscreated by the declaration. Each of the strings can be accessed by the associated pointer in arrayas array[0], ... array[3].
array上面声明的元素是指向 char 类型的指针。具体来说,元素是指向由声明创建的字符串文字的指针。每个字符串都可以通过arrayas 中的关联指针访问array[0], ... array[3]。
A pointer to pointer to type(double-pointer), is exactly what its name implies. It is a pointer, that holds a pointeras its value. In basic terms, it is a pointer that points to another pointer. It can be used to access the members of the array above by assigning the address of arraylike:
一个指针,指针型(双指针),正是它的名字所暗示的。它是一个指针,它持有一个指针作为它的值。在基本术语中,它是一个指向另一个指针的指针。它可以用来通过分配arraylike的地址来访问上面数组的成员:
char **p = array;
Where p[1]or *(p + 1)points to "brown fox", etc.
哪里p[1]或*(p + 1)指向"brown fox"等。
Alternatively, a number of pointer to pointer to type can be dynamically allocated and used to create an array of pointers to type, that can then be allocated and reallocated to handle access or storage of an unknown number of elements. For example, a brief example to read an unknown number of lines from stdin, you might see:
或者,可以动态分配多个指向类型指针的指针并用于创建指向类型的指针数组,然后可以分配和重新分配该数组以处理对未知数量元素的访问或存储。例如,从 中读取未知行数的简短示例stdin,您可能会看到:
#define MAXL 128
#define MAXC 512
...
char **lines = NULL;
char buf[MAXC] = {0};
lines = malloc (MAXL * sizeof *lines);
size_t index = 0;
...
while (fgets (buf, MAXC, stdin)) {
lines[index++] = strdup (buf);
if (index == MAXL)
/* reallocate lines */
}
Above you have lines, a pointer-to-pointer-to-char, initially NULL, that is use to allocate MAXL(128) pointers-to-char. Lines are then read from stdininto buf, after each successful read, memory is allocated to hold the contents of bufand the resulting start address for each block of memory is assigned to each pointer line[index]where indexis 0-127, and upon increment of indexto 128, indexis reallocated to provide additional pointers and the read continues.
上面有lines一个指向字符的指针,最初NULL用于分配MAXL(128 个)指向字符的指针。然后从stdininto 中读取行buf,在每次成功读取后,分配内存以保存 的内容,buf并将每个内存块的结果起始地址分配给每个指针line[index],其中index是0-127,并在index增加到 128 时index重新分配以提供额外的指针和读取继续。
What makes the topic larger than can be handled in any one answer is that an array of pointersor pointer to pointer to typecan be to any type. (int, struct, or as a member of a struct to different type, or function, etc...) They can be used linked-lists, in the return of directory listings (e.g opendir), or in any additional number of ways. They can be statically initialized, dynamically allocated, passed as function parameters, etc... There are just far too many different contexts to cover them all. But in all instances, they will follow the general rules seen here and in the other answer here and in 1,000's more answers here on StackOverflow.
使主题比任何一个答案都可以处理的更大的原因是指针数组或指向类型的指针的指针可以指向any type。( int, struct, 或作为不同类型结构的成员, orfunction等...) 它们可以用于链表,返回目录列表(例如opendir),或以任何其他方式使用。它们可以被静态初始化、动态分配、作为函数参数传递等等......有太多不同的上下文来涵盖它们。但在所有情况下,他们都将遵循此处和此处的其他答案以及 StackOverflow 上的 1,000 多个答案中看到的一般规则。
I'll end with a short example you can use to look at the different basic uses of the array and double-pointer. I have provided additional comments in the source. This just provides a handful of different basic uses and of static declaration and dynamic allocation:
我将以一个简短的示例结束,您可以使用它来查看数组和双指针的不同基本用途。我在来源中提供了额外的评论。这只是提供了一些不同的基本用途以及静态声明和动态分配:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (void) {
/* array is a static array of 4 pointers to char, initialized to the
4 string-literals that a part of the declaration */
char *array[] = { "The quick",
"brown fox",
"jumps over",
"the lazy dog." };
/* p is a pointer-to-pointer-to-char assigned the address of array */
char **p = array;
/* lines is a pointer-to-pointer-to-char initialized to NULL, used
below to allocate 8 pointers and storage to hold 2 copes of array */
char **lines = NULL;
size_t narray = sizeof array/sizeof *array;
size_t i;
printf ("\nprinting each string-literal at the address stored by\n"
"each pointer in the array of ponters named 'array':\n\n");
for (i = 0; i < narray; i++)
printf (" %s\n", array[i]);
printf ("\nprinting each string using a pointer to pointer to char 'p':\n\n");
for (i = 0; i < narray; i++, p++)
printf (" %s\n", *p);
p = array;
printf ("\nprinting each line using a pointer to pointer"
" to char 'p' with array notation:\n\n");
for (i = 0; i < narray; i++)
printf (" %s\n", p[i]);
/* allocate 8 pointers to char */
lines = malloc (2 * narray * sizeof *lines);
/* allocate memory and copy 1st 4-strings to lines (long way) */
for (i = 0; i < narray; i++) {
size_t len = strlen (array[i]);
lines[i] = malloc (len * sizeof **lines + 1);
strncpy (lines[i], array[i], len);
lines[i][len] = 0;
}
/* allocate memory and copy 1st 4-strings to lines
(using strdup - short way) */
// for (i = 0; i < narray; i++)
// lines[i] = strdup (array[i]);
/* allocate memory and copy again as last 4-strings in lines */
p = array;
for (i = 0; i < narray; i++, p++)
lines[i+4] = strdup (*p);
p = lines; /* p now points to lines instead of array */
printf ("\nprinting each allocated line in 'lines' using pointer 'p':\n\n");
for (i = 0; i < 2 * narray; i++)
printf (" %s\n", p[i]);
/* free allocated memory */
for (i = 0; i < 2 * narray; i++)
free (lines[i]);
free (lines);
return 0;
}
Let me know if you have any questions. It a large topic with a relatively small set of rules that can be applied in whole lot of different ways and in different contexts.
如果您有任何问题,请告诉我。它是一个包含相对较小的规则集的大主题,可以以多种不同的方式在不同的上下文中应用。
回答by R Sahu
My professor wrote that
**arrayis same as*array[]
我的教授写的
**array和*array[]
That is true in some contexts and not true in other contexts.
这在某些情况下是正确的,而在其他情况下则不然。
If used in a function as argument,
如果在函数中用作参数,
void foo(int **array) {}
is the same as
是相同的
void foo(int *array[]) {}
When declared as variables,
当声明为变量时,
int **array;
is not the same as
不一样
int *array[];
Disclaimer:This is by no means an exhaustive list of where they are same and where they are different.
免责声明:这绝不是它们相同和不同之处的详尽清单。

