为什么函数(char * array [])是有效的函数定义而不是(C中的char(* array)[]?

时间:2011-08-04 04:37:55

标签: c

认为是因为前者是指向char的指针数组,而后者是指向char数组的指针,我们需要正确指定指向的对象的大小为我们的功能定义。在前者;

function(char * p_array[])

指向的对象的大小已经包含(它是指向char的指针),但后者是

function(char (*p_array)[])

需要p_array指向的数组的大小作为p_array定义的一部分吗? 我正处于这个阶段,我已经考虑了这个问题太长时间了,只是让自己感到困惑,如果我的推理是正确的,请有人告诉我。

4 个答案:

答案 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)。一些编译器支持将其作为扩展,但这是非标准的符合。