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

Posted

技术标签:

【中文标题】将数组和数组指针传递给C中的函数之间的区别【英文标题】:Difference between passing array and array pointer into function in C 【发布时间】:2011-07-31 04:58:09 【问题描述】:

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

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


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

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

【问题讨论】:

【参考方案1】:

首先,一些standardese:

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

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

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

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

给定以下代码:

int main(void)

  int arr[10];
  foo(arr);
  ...

在对foo 的调用中,数组表达式arr 不是sizeof& 的操作数,因此其类型从“int 的10 元素数组”隐式转换为“指向int 的指针”根据 6.2.3.1/3。因此,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个元素的数组。

【讨论】:

在使用(至少一些较旧的)MSVC C++ 编译器时存在差异,因为编译器在这两种情况下错误地对函数名称进行了不同的处理(同时认识到它们在其他情况下是相同的),导致在链接问题。请参阅此处的“无法修复”错误报告connect.microsoft.com/VisualStudio/feedback/details/326874/…【参考方案2】:

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

【讨论】:

@Kaushik:虽然在这种情况下它们是相同的,但请记住它们并不相同in the general case @BlueRaja: 是的,这是C语言的缺陷之一。函数参数的声明与局部变量的声明非常相似,但有一些微妙之处容易让粗心的程序员陷入困境的差异(例如这种数组到指针的自动转换)。【参考方案3】:

不,它们之间没有区别。为了测试我在 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 中反汇编 ma​​in 函数时,我得到完全相同的汇编代码,如下所示:

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

所以这个调用的两个版本没有区别,至少编译器对它们的威胁是一样的。

【讨论】:

对不起,但这仅证明某些版本的 gcc 在 x86 上为两者生成了相同的程序集。正确答案,错误解释。

以上是关于将数组和数组指针传递给C中的函数之间的区别的主要内容,如果未能解决你的问题,请参考以下文章

c ++按值或指向函数语法的指针传递数组

指针数组内容在传递给 C 中的函数时被擦除

c语言 指针传参

数组名作函数参数时,实参与形参变量之间的数据传递是?

将指针数组传递给函数指针数组的 C++ 问题

c_cpp 将数组指针传递给函数