为什么函数(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_arraychar数组的指针。 但是当它作为函数参数出现时,它需要具有固定的大小。 您需要提供尺寸,这也将变得有效。

注意:
当Q被标记为C ++时,会添加以下答案,并从C ++的角度回答。 标记更改为仅C,两个提到的样本在C中都有效。

是的,你的推理是正确的。
如果您尝试编译编译器给出的错误是:

 parameter 'p_array' includes pointer to array of unknown bound 'char []' 

在C ++中,数组大小需要在编译时修复。 C ++标准也禁止使用可变长度数组(VLA)。 一些编译器支持将其作为扩展,但这是非标准的符合。