为什么函数(char * array )是有效的函数定义而不是(C中的char(* array)?
我认为这是因为前者是一个指向char的指针数组,而后者是一个指向char数组的指针,我们需要正确指定我们的函数定义所指向的对象的大小。 在前者;
function(char * p_array[])
指向的对象的大小已经包含(它是指向char的指针),但是后者
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];
有一个catch,而catch是一个带有[]
的数组类型是一个不完整的类型。 您可以传递指向不完整类型的指针,但某些操作不起作用,因为它们需要完整的类型。 例如,这不起作用:
void func(int (*x)[]) { x[2][5] = 900; // Error }
这是一个错误,因为为了找到x[2]
的地址,编译器需要知道x[0]
和x[1]
有多大。 但是x[0]
和x[1]
类型为int []
– 一个不完整的类型,没有关于它有多大的信息。 如果您想象该类型的“未衰减”版本将是什么,这将是更清楚的,这是int x[][]
– 显然无效C.如果你想在C中传递一个二维数组,你有一些选择:
-
传递带有size参数的一维数组。
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)。 您将看到许多使用数组数组或手动计算数组偏移的代码。
这两个声明非常不同。 在函数参数声明中,直接应用于参数名称的[]
声明符完全等同于*
,因此您的第一个声明在所有方面都完全相同:
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]
不允许。
因为,
(1) function(char * p_array[])
相当于char **p_array
; 即一个有效的双指针。
(2) function(char (*p_array)[])
你是对的, p_array
是char
数组的指针。 但是当它作为函数参数出现时,它需要具有固定的大小。 您需要提供尺寸,这也将变得有效。
注意:
当Q被标记为C ++时,会添加以下答案,并从C ++的角度回答。 标记更改为仅C,两个提到的样本在C中都有效。
是的,你的推理是正确的。
如果您尝试编译编译器给出的错误是:
parameter 'p_array' includes pointer to array of unknown bound 'char []'
在C ++中,数组大小需要在编译时修复。 C ++标准也禁止使用可变长度数组(VLA)。 一些编译器支持将其作为扩展,但这是非标准的符合。