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

时间:2011-04-06 21:40:58

标签: c arrays function parameter-passing space-efficiency

C中的两个函数有什么区别?

void f1(double a[]) {
   //...
}

void f2(double *a) {
   //...
}

如果我要在一个相当长的数组上调用这些函数,这两个函数的行为是否会有所不同,它们会占用更多的空间吗?

3 个答案:

答案 0 :(得分:107)

首先,一些standardese

6.7.5.3函数声明符(包括原型)
...
7参数声明为“ type ”的数组应调整为''限定指针 输入'',其中类型限定符(如果有)是在[]内指定的类型限定符。 数组类型推导。如果关键字static也出现在[]内 数组类型派生,然后对每个函数调用,对应的值 实际参数应提供对至少具有至少数量的数组的第一个元素的访问 size表达式指定的元素。

因此,简而言之,声明为T a[]T a[N]的任何函数参数都被视为,就像它被声明为T *a一样。

那么,为什么将数组参数视为声明为指针?原因如下:

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

给出以下代码:

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

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

由于6.7.5.3/7,您可以将foo写为

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

但它将被解释为

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

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

6.99.5.3/7中的最后一句是用C99引入的,基本上意味着如果你有一个像

这样的参数声明
void foo(int a[static 10])
{
  ...
}

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

答案 1 :(得分:28)

差异纯粹是语法上的。在C中,当数组表示法用于函数参数时,它会自动转换为指针声明。

答案 2 :(得分: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中反汇编 main 函数时,我得到完全相同的汇编代码,如下所示:

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

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