将数组和数组指针传递到C中的函数之间的区别


Answers:


114

首先,一些标准语

6.7.5.3函数声明符(包括原型)
...
7参数声明为“ 类型数组”应调整为“ 类型的限定指针 ”,其中类型限定符(如果有)是指定的在[]类型的数组派生。如果关键字static也出现在[]的数组类型派生中,则对于函数的每次调用,相应实际参数的值应提供对数组第一个元素的访问,该元素的大小至少与size指定的数量相同表达。

简而言之,任何声明为T a[]或的函数参数T a[N]都将被视为声明T *a

那么,为什么将数组参数当作声明为指针一样对待呢?原因如下:

6.3.2.1左值,数组和函数指示符
...
3除非它是运算sizeof符或一元运算&符的操作数,或者是用于初始化数组的字符串文字,否则表达式的类型为“ array type ' '被转换成类型的表达式‘’指针类型 ‘’指向阵列对象的初始元素,不是左值。如果数组对象具有寄存器存储类,则该行为是不确定的。

给出以下代码:

int main(void)
{
  int arr[10];
  foo(arr);
  ...
}

在对的调用中foo,数组表达式arr不是sizeof或的操作数&,因此根据6.2.3.1/3 ,其类型从“的10个元素的数组int” 隐式转换为“指向的指针int”。这样,foo将接收一个指针值,而不是一个数组值。

由于6.7.5.3/7,你可以写foo

void foo(int a[]) // or int a[10]
{
  ...
}

但它会被解释为

void foo(int *a)
{
  ...
}

因此,两种形式是相同的。

6.7.5.3/7中的最后一句话是C99引入的,基本上意味着如果您有一个参数声明,例如

void foo(int a[static 10])
{
  ...
}

对应的实际参数a必须是至少包含 10个元素的数组。


1
使用(至少某些较旧的)MSVC C ++编译器存在差异,这是因为在两种情况下编译器错误地对函数名称进行了不同的处理(同时意识到它们是相同的),从而导致链接问题。请参阅“不会解决”错误报告这里connect.microsoft.com/VisualStudio/feedback/details/326874/...
greggo

29

区别纯粹是语法上的。在C语言中,当数组符号用作函数参数时,它将自动转换为指针声明。


1
@Kaushik:尽管在这种情况下它们是相同的,但请记住,在一般情况下
BlueRaja-Danny Pflughoeft

@BlueRaja:是的,这是C的陷阱之一。函数参数的声明与局部变量的声明非常相似,但是有一些细微的差异(例如,此数组到指针的自动转换)容易咬粗心的程序员。
Thomas Pornin 2011年

0

不,两者之间没有区别。为了测试,我在Dev C ++(mingw)编译器中编写了以下C代码:

#include <stdio.h>

void function(int* array) {
     int a =5;
}

void main() {  
     int array[]={2,4};
     function(array);
     getch();
}

当我在IDA的两个调用版本的二进制文件的版本的.exe中反汇编主要功能时,我得到的汇编代码完全相同,如下所示:

push    ebp
mov     ebp, esp
sub     esp, 18h
and     esp, 0FFFFFFF0h
mov     eax, 0
add     eax, 0Fh
add     eax, 0Fh
shr     eax, 4
shl     eax, 4
mov     [ebp+var_C], eax
mov     eax, [ebp+var_C]
call    sub_401730
call    sub_4013D0
mov     [ebp+var_8], 2
mov     [ebp+var_4], 4
lea     eax, [ebp+var_8]
mov     [esp+18h+var_18], eax
call    sub_401290
call    _getch
leave
retn

因此,此调用的两个版本之间没有区别,至少编译器对它们的威胁相同。


18
抱歉,但这仅证明某些版本的gcc在x86上为两者生成了相同的程序集。正确答案,错误解释。
lambdapower
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.