数组表示法衰减为指针符号 - 仅用于函数参数?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数组表示法衰减为指针符号 - 仅用于函数参数?相关的知识,希望对你有一定的参考价值。
我正在学习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是函数的形式参数“。这是什么意思?为什么会这样?
我认为他意味着你可能不会声明这样的数组
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
", sizeof( pt ) );
return 0;
}
程序输出是
sizeof( pt ) = 32
普通数组和函数参数数组之间的类似语法是一大堆混乱的根源。
如果声明一个普通数组,你可以这样做:
int arr[3] = {1,2,3};
或者你可以这样做:
int arr[] = {1,2,3};
这些形式是100%等效的,后者只是告诉编译器计算元素的数量并为你填写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[]
写为函数参数时,它是一个不完整的类型,就像我们在上面没有初始化列表时编写它一样。它不能被使用 - 它并不意味着“函数接受任何数组大小”,但在实践中将会发生这种情况。因为编译器不关心这里的数组大小,因为它是一个函数参数,无论如何编译器将用指向第一个元素的指针替换它。所以无论我们在[ ]
之间键入什么,我们最终都会得到int*
。
数组衰减规则适用于任何参数类型。因此,如果您使用2D数组(实际上是数组数组),它会衰减为第一个元素的指针。这与指向第一个数组的指针相同。所以你可以写int pt[][4]
它会工作。 int pt[666][4]
也将如此。无论如何,你最终会得到int (*)[4]
。
但是这个数组衰减规则并不适用于“递归”:C编译器只能看到一个数组。它恰好是一个数组数组,但编译器并不关心。所以我们不能写int arr[][]
,因为这会导致int (*)[]
,它是一个指向不完整类型的数组指针,不允许作为函数参数。
以上是关于数组表示法衰减为指针符号 - 仅用于函数参数?的主要内容,如果未能解决你的问题,请参考以下文章