代码之家  ›  专栏  ›  技术社区  ›  Thor

数组表示法衰减为指针表示法-仅用于函数参数?

  •  4
  • Thor  · 技术社区  · 8 年前

    通过遵循本书中的处理方法,我目前正在学习C函数如何接受多维数组 C primer plus , by Stephen Prata (6th edition) .

    在书中,作者提到处理多维数组的函数可以声明为。。。

    void somefunction( int (* pt)[4] );
    

    或者,如果(且仅当)pt是 函数,您可以按如下方式声明它:

    void somefunction( int pt[][4] );
    

    我知道在C中,传入函数的数组将衰减为指向相应类型的指针。所以 pt 在里面 int pt[][4] 将衰变为 int (* pt)[4] ,它是指向4的数组的指针 int s

    但我不明白为什么这种行为只有在pt是函数的形式参数时才会发生。这意味着什么?为什么会这样?

    2 回复  |  直到 8 年前
        1
  •  4
  •   Vlad from Moscow    8 年前

    我想他的意思是你不能声明这样的数组

    int pt[][4];
    

    在程序中(具有外部或内部链接的声明除外),因为它是一个不完整的类型,数组的大小未知。

    但是,您可以将此类声明用作参数声明

    void somefunction( int pt[][4] );
    

    因为编译器将参数调整为类型的指针

    void somefunction( int ( *pt )[4] );
    

    指针总是完整的类型。

    因此,例如,这些函数声明

    void somefunction( int pt[100][4] );
    void somefunction( int pt[10][4] );
    void somefunction( int pt[][4] );
    

    是等价的,并声明相同的一个函数。

    下面是一个使用外部链接声明不完整类型的数组(当声明不是定义时)的示例。

    #include <stdio.h>
    
    int pt[2][4];
    
    int main(void) 
    {
        extern int pt[][4];
    
        printf( "sizeof( pt ) = %zu\n", sizeof( pt ) );
    
        return 0;
    }
    

    程序输出为

    sizeof( pt ) = 32
    
        2
  •  2
  •   Lundin    8 年前

    普通数组和函数参数数组之间的相似语法是造成大量混淆的原因。

    如果声明普通数组,可以这样做:

    int arr[3] = {1,2,3};
    

    或者您可以执行以下操作:

    int arr[] = {1,2,3};
    

    这些表单是完全等效的,后者只是告诉编译器计算元素的数量并填写 3 为你。

    类似地,您可以使用2D数组来执行此操作,但只能使用最左侧的维度:

    int arr[][3] = { {1,2,3}, {1,2,3} };
    

    这与 int arr[2][3] .

    所有这些都适用于任何普通的本地或全局数组。值得注意的是,上述方法之所以有效,是因为存在初始值设定项列表。没有初始值设定项列表,我们无法写入 int arr[]; -这不是有效的C语法。到现在为止,一直都还不错。


    为了产生最大程度的混淆,C还允许将函数参数声明为 void func (int arr[3]); 或者,或者 void func (int arr[]) 。事实证明,这两种形式也是等效的。但原因完全不同!

    因为在具体的函数情况下,数组声明总是被调整(“衰减”)为指向第一个元素的指针。所以 int arr[3] 作为函数声明的一部分时,100%等效于 int* .

    当我们写作时 int arr[] 作为一个函数参数,它是一个不完整的类型,就像我们在上面没有初始值设定项列表的情况下编写它一样。它不能被使用-它并不意味着“函数接受任何数组大小”,尽管在实践中会发生这种情况。因为编译器不关心这里的数组大小,因为它是一个函数参数,编译器将用指向第一个元素的指针来替换它。所以不管我们在 [ ] 我们以 内景* .

    数组衰减规则适用于任何参数类型。因此,如果使用一个2D数组,它实际上是一个数组数组,它会衰减为第一个元素的指针。它与指向第一个数组的指针相同。所以你可以写 int pt[][4] 它会起作用的。我也会的 int pt[666][4] 。你最终会 int (*)[4] 不管怎样

    但是这个数组衰减规则并不是“递归地”应用的:C编译器只看到一个数组。它碰巧是一个数组数组,但编译器并不关心。所以我们不能写 int arr[][] ,因为这样会导致 int (*)[] 它是指向不完整类型的数组指针,不允许将其作为函数参数。