我认为这是因为前者是指向char类型指针的数组,而后者是指向char类型数组的指针,我们需要正确指定被指向的对象的大小以便进行函数定义。在前者中;
function(char * p_array[])
指针所指向的对象的大小已经包含在内(它是一个指向字符的指针),但后者...
function(char (*p_array)[])
需要将p_array指向数组的大小作为p_array定义的一部分吗?我已经思考了很长时间,现在自己已经搞糊涂了,请有人告诉我我的推理是否正确。
我认为这是因为前者是指向char类型指针的数组,而后者是指向char类型数组的指针,我们需要正确指定被指向的对象的大小以便进行函数定义。在前者中;
function(char * p_array[])
function(char (*p_array)[])
需要将p_array指向数组的大小作为p_array定义的一部分吗?我已经思考了很长时间,现在自己已经搞糊涂了,请有人告诉我我的推理是否正确。
在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[0]
和x[1]
有多大才能找到x[2]
的地址。但是x[0]
和x[1]
的类型是int[]
——这是一种不完整的类型,没有关于其大小的信息。如果您想象一下类型的“未衰减”版本,即int x[][]
,就会更清楚,它显然是无效的C语言代码。如果您想在C中传递二维数组,有几个选项:
传递一个带有大小参数的一维数组。
void func(int n, int x[])
{
x[2*n + 5] = 900;
}
使用指向行的指针数组。如果你有真正的二维数据,这种方法可能有些笨拙。void func(int *x[])
{
x[2][5] = 900;
}
使用固定大小。
void func(int x[][5])
{
x[2][5] = 900;
}
使用变长数组(仅限C99,因此可能不适用于微软编译器)。
// 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)。您会看到很多代码使用数组的数组或手动计算数组偏移量。char (*p_array)[]
是指向不完整类型的指针,因此您不能对其进行解引用。 - caf(*p_array)[j]
是有效的,但p_array[i][j]
则无效。 - Dietrich Epp注意:
以下答案是从C++的角度回答的,当标记为C++时添加了该答案。如果标记更改为仅C,则两个提到的示例在C中都是有效的。
是的,你的推理是正确的。
如果您尝试编译编译器给出的错误,则会出现:
parameter ‘p_array’ includes pointer to array of unknown bound ‘char []’
这两个声明是非常不同的。在函数参数声明中,对参数名称直接应用[]
的声明符与*
完全等价,因此你的第一个声明在所有方面都与以下声明完全相同:
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_array)[1]
,这是可以的。 - caf因为,
(1) function(char * p_array[])
等同于char **p_array
,即有效的双指针。
(2) function(char (*p_array)[])
您说得对,p_array
是指向char
数组的指针。但是,当它作为函数参数出现时,它需要具有固定的大小。您需要提供大小,这样它也将变得有效。
char (*p)[3] = &a;
其中 char a[3];
。 - iammilind-pendantic -ansi -Wall -Wextra
进行双重检查,因为找到适当的部分需要更多时间。(适当的部分是n1570第6.7.6.2和6.7.6.3节,尽管您基本上必须阅读这两个部分才能弄清楚这是可以的。它们不是VLA,而是不完整类型的数组。 VLA是C99中的新功能,但不完整类型的数组与C本身一样古老。) - Dietrich Epp