我认为是因为前者是指向char的指针数组,而后者是指向char数组的指针,我们需要正确指定指向的对象的大小为我们的功能定义。在前者;
function(char * p_array[])
指向的对象的大小已经包含(它是指向char的指针),但后者是
function(char (*p_array)[])
需要p_array指向的数组的大小作为p_array定义的一部分吗? 我正处于这个阶段,我已经考虑了这个问题太长时间了,只是让自己感到困惑,如果我的推理是正确的,请有人告诉我。
答案 0 :(得分:14)
两者在C 中都有效,但不是C ++ 。你通常是正确的:
char *x[]; // array of pointers to char
char (*y)[]; // pointer to array of char
但是,如果数组显示为函数参数,则它们会衰减为指针。所以他们变成了:
char **x; // Changes to pointer to array of pointer to char
char (*y)[]; // No decay, since it's NOT an array, it's a pointer to an array
在C中的数组类型中,允许未指定其中一个大小。这必须是最左边的一个(哎呀,我最初说的最右边)。所以,
int valid_array[][5]; // Ok
int invalid_array[5][]; // Wrong
(你可以链接它们......但我们很少有理由这样做......)
int (*convoluted_array[][5])[][10];
有一个问题,,问题是其中包含[]
的数组类型是不完整类型。您可以将指针传递给一个不完整的类型但某些操作不起作用,因为它们需要一个完整的类型。例如,这不起作用:
void func(int (*x)[])
{
x[2][5] = 900; // Error
}
这是一个错误,因为为了找到x[2]
的地址,编译器需要知道x[0]
和x[1]
的大小。但x[0]
和x[1]
类型为int []
- 类型不完整,没有关于它有多大的信息。如果您想象该类型的“未衰减”版本是什么,int x[][]
- 显然无效C.如果您想要在C中传递二维数组,那么这将变得更加清晰几个选项:
传递一个带尺寸参数的一维数组。
void func(int n, int x[])
{
x[2*n + 5] = 900;
}
使用指向行的指针数组。如果您拥有真正的2D数据,这有点笨拙。
void func(int *x[])
{
x[2][5] = 900;
}
使用固定大小。
void func(int x[][5])
{
x[2][5] = 900;
}
使用可变长度数组(仅限C99,因此它可能不适用于Microsoft编译器)。
// There's some funny syntax if you want 'x' before 'width'
void func(int n, int x[][n])
{
x[2][5] = 900;
}
即使对于C退伍军人来说,这也是一个常见问题。许多语言缺乏对真实的,可变大小的多维数组(C ++,Java,Python)的内在“开箱即用”支持,尽管有一些语言可以使用它(Common Lisp,Haskell,Fortran)。您将看到许多使用数组数组或手动计算数组偏移的代码。
答案 1 :(得分:3)
这两个声明非常不同。在函数参数声明中,直接应用于参数名称的[]
声明符完全等同于*
,因此您的第一个声明在所有方面都与此完全相同:
function(char **p_array);
但是, 不会递归地应用于参数类型。您的第二个参数具有类型char (*)[]
,它是指向未知大小的数组的指针 - 它是指向不完整类型的指针。您可以愉快地声明具有此类型的变量 - 以下是有效的变量声明:
char (*p_array)[];
就像指向任何其他不完整类型的指针一样,你不能对这个变量(或你的函数参数)执行任何指针算术 - 这就是你出错的地方。请注意,[]
运算符指定为a[i]
与*(a+i)
相同,因此该运算符无法应用于指针。当然,您可以愉快地将它用作指针,因此这是有效的:
void function(char (*p_array)[])
{
printf("p_array = %p\n", (void *)p_array);
}
此类型还兼容指向char
的任何其他固定大小数组的指针,因此您也可以这样做:
void function(char (*p_array)[])
{
char (*p_a_10)[10] = p_array;
puts(*p_a_10);
}
......甚至这个:
void function(char (*p_array)[])
{
puts(*p_array);
}
(尽管这样做有一点很重要:你也可以用类型char *
声明参数)。
请注意,虽然允许*p_array
,但p_array[0]
不是。{/ p>
答案 2 :(得分:2)
由于,
(1) function(char * p_array[])
相当于char **p_array
;即一个有效的双指针。
(2) function(char (*p_array)[])
你是对的,p_array
是指向char
数组的指针。但是当它作为函数参数出现时,它需要具有固定的大小。您需要提供尺寸,这也将变得有效。
答案 3 :(得分:2)
注意:
当Q标记为C ++时,会添加以下答案,并从C ++的角度回答。标记为仅更改为C,两个提到的样本在C中都有效。
是的,你的推理是正确的。
如果您尝试编译编译器给出的错误是:
parameter ‘p_array’ includes pointer to array of unknown bound ‘char []’
在C ++中,数组大小需要在编译时修复。 C ++标准也禁止使用可变长度数组(VLA)。一些编译器支持将其作为扩展,但这是非标准的符合。