双指针与指针数组(**数组与*数组[])
Double pointer vs array of pointers(**array vs *array[])
我不清楚这两个之间有什么区别。我的教授写道 **array 与 *array[] 相同,我们看到了一个他使用 **array 的例子(所以在 classes 我试着用 *array[] 交换它但没有用),谁能告诉我这两个是否真的和他写的一样?无论如何,class 是关于动态内存分配的
@我一改双指针,这一行就开始报错
lines = malloc(sizeof(char*));
和其他一些正在重新分配内存的地方
@2 见鬼,这是完整的代码
对于下面的评论,不,[] 里面什么也没有,因为他的陈述是
**array = *array[]
重大更新
对于给您带来的不便,我深表歉意,写这篇文章时我实在是太累了post,这是完整的代码,没有任何修改
#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;
}
My professor wrote that **array
is same as *array[]
这在某些情况下是正确的,而在其他情况下则不然。
如果在函数中用作参数,
void foo(int **array) {}
与
相同
void foo(int *array[]) {}
声明为变量时,
int **array;
与
不一样
int *array[];
如果你在问题中引用的代码是你的教授给你的,作为使用指向指针的指针数组的示例,我不确定 class 实际上会有多大用处做。我怀疑它要么作为调试练习提供,要么可能是您尝试解决问题。无论如何,如果您只是在启用 Warnings 的情况下进行编译,在继续调试代码之前,您会发现许多需要注意的问题。
关于您引用的代码,虽然您可以自由使用全局文本缓冲区,但不使用全局缓冲区并根据需要传递指向数据的指针会更好。有一些实例、各种回调函数等需要全局数据,但根据经验,这些都是例外而不是规则。
你的问题基本上可以归结为“如何正确使用指针数组和双指针(指针到指针到类型)变量。一个主题无法完全涵盖回答是因为有太多的情况和上下文可以(或应该)使用其中一个或另一个以及为什么。但是,一些示例有望帮助您理解基本差异。
从指向类型(例如char *array[]
)的指针数组开始。它通常以这种形式被视为函数参数。当声明为变量时,它后面跟着一个初始化。例如:
char *array[] = { "The quick",
"brown fox",
"jumps over",
"the lazy dog." };
char *array[];
作为变量声明本身是无效的,因为 [..]
之间缺少数组大小。当全局使用时,如您的示例所示,编译器将接受声明,但会 警告 该声明假定具有 一个元素 .
上面声明的array
的元素是指向char类型的指针。具体来说,这些元素是指向由声明创建的 string-literals 的指针。 array
中的关联指针可以访问每个字符串,如 array[0], ... array[3]
.
A pointer to pointer to pointer to type (double-pointer),顾名思义。它是一个指针,将一个指针作为其值。简单来说,它是一个指向另一个指针的指针。它可以通过分配array
的地址来访问上面数组的成员,如:
char **p = array;
其中 p[1]
或 *(p + 1)
指向 "brown fox"
,等等
或者,可以动态分配多个指向类型的指针并用于创建指向类型的指针数组,然后可以分配和重新分配该数组以处理未知数量元素的访问或存储。例如,一个从 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 */
}
上面有 lines
,一个指向字符的指针,最初是 NULL
,用于分配 MAXL
(128) 个指向字符的指针.然后从 stdin
读取行到 buf
,每次成功读取后,分配内存以保存 buf
的内容,并将每个内存块的起始地址分配给每个指针line[index]
其中 index
是 0-127
,并且在 index
增加到 128 时,重新分配 index
以提供额外的指针并继续读取。
使该主题大于任何一个答案都无法处理的原因是 指针数组 或 指向类型指针的指针可以是任何 type
。 (int
、struct
或作为不同类型的结构成员,或 function
,等等...)它们可以用于 linked-lists,在目录列表的 return 中(例如 opendir
),或以任何其他方式。它们可以静态初始化、动态分配、作为函数参数传递等等……有太多不同的上下文无法涵盖所有内容。但在所有情况下,他们都将遵循此处和此处其他答案以及 Whosebug 上 1,000 多个答案中看到的一般规则。
我将以一个简短的示例作为结尾,您可以使用它来了解数组和双指针的不同基本用法。我在源代码中提供了额外的评论。这只是提供了一些不同的基本用法以及静态声明和动态分配:
#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;
}
如果您有任何问题,请告诉我。这是一个包含相对较少规则集的大主题,可以以多种不同的方式应用在不同的上下文中。
我不清楚这两个之间有什么区别。我的教授写道 **array 与 *array[] 相同,我们看到了一个他使用 **array 的例子(所以在 classes 我试着用 *array[] 交换它但没有用),谁能告诉我这两个是否真的和他写的一样?无论如何,class 是关于动态内存分配的
@我一改双指针,这一行就开始报错
lines = malloc(sizeof(char*));
和其他一些正在重新分配内存的地方
@2 见鬼,这是完整的代码
对于下面的评论,不,[] 里面什么也没有,因为他的陈述是
**array = *array[]
重大更新
对于给您带来的不便,我深表歉意,写这篇文章时我实在是太累了post,这是完整的代码,没有任何修改
#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;
}
My professor wrote that
**array
is same as*array[]
这在某些情况下是正确的,而在其他情况下则不然。
如果在函数中用作参数,
void foo(int **array) {}
与
相同void foo(int *array[]) {}
声明为变量时,
int **array;
与
不一样int *array[];
如果你在问题中引用的代码是你的教授给你的,作为使用指向指针的指针数组的示例,我不确定 class 实际上会有多大用处做。我怀疑它要么作为调试练习提供,要么可能是您尝试解决问题。无论如何,如果您只是在启用 Warnings 的情况下进行编译,在继续调试代码之前,您会发现许多需要注意的问题。
关于您引用的代码,虽然您可以自由使用全局文本缓冲区,但不使用全局缓冲区并根据需要传递指向数据的指针会更好。有一些实例、各种回调函数等需要全局数据,但根据经验,这些都是例外而不是规则。
你的问题基本上可以归结为“如何正确使用指针数组和双指针(指针到指针到类型)变量。一个主题无法完全涵盖回答是因为有太多的情况和上下文可以(或应该)使用其中一个或另一个以及为什么。但是,一些示例有望帮助您理解基本差异。
从指向类型(例如char *array[]
)的指针数组开始。它通常以这种形式被视为函数参数。当声明为变量时,它后面跟着一个初始化。例如:
char *array[] = { "The quick",
"brown fox",
"jumps over",
"the lazy dog." };
char *array[];
作为变量声明本身是无效的,因为 [..]
之间缺少数组大小。当全局使用时,如您的示例所示,编译器将接受声明,但会 警告 该声明假定具有 一个元素 .
上面声明的array
的元素是指向char类型的指针。具体来说,这些元素是指向由声明创建的 string-literals 的指针。 array
中的关联指针可以访问每个字符串,如 array[0], ... array[3]
.
A pointer to pointer to pointer to type (double-pointer),顾名思义。它是一个指针,将一个指针作为其值。简单来说,它是一个指向另一个指针的指针。它可以通过分配array
的地址来访问上面数组的成员,如:
char **p = array;
其中 p[1]
或 *(p + 1)
指向 "brown fox"
,等等
或者,可以动态分配多个指向类型的指针并用于创建指向类型的指针数组,然后可以分配和重新分配该数组以处理未知数量元素的访问或存储。例如,一个从 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 */
}
上面有 lines
,一个指向字符的指针,最初是 NULL
,用于分配 MAXL
(128) 个指向字符的指针.然后从 stdin
读取行到 buf
,每次成功读取后,分配内存以保存 buf
的内容,并将每个内存块的起始地址分配给每个指针line[index]
其中 index
是 0-127
,并且在 index
增加到 128 时,重新分配 index
以提供额外的指针并继续读取。
使该主题大于任何一个答案都无法处理的原因是 指针数组 或 指向类型指针的指针可以是任何 type
。 (int
、struct
或作为不同类型的结构成员,或 function
,等等...)它们可以用于 linked-lists,在目录列表的 return 中(例如 opendir
),或以任何其他方式。它们可以静态初始化、动态分配、作为函数参数传递等等……有太多不同的上下文无法涵盖所有内容。但在所有情况下,他们都将遵循此处和此处其他答案以及 Whosebug 上 1,000 多个答案中看到的一般规则。
我将以一个简短的示例作为结尾,您可以使用它来了解数组和双指针的不同基本用法。我在源代码中提供了额外的评论。这只是提供了一些不同的基本用法以及静态声明和动态分配:
#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;
}
如果您有任何问题,请告诉我。这是一个包含相对较少规则集的大主题,可以以多种不同的方式应用在不同的上下文中。