C语言 C中将数组和数组指针传递给函数的区别

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5573310/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 08:17:26  来源:igfitidea点击:

Difference between passing array and array pointer into function in C

carraysfunctionparameter-passingspace-efficiency

提问by Kaushik Shankar

What is the difference between the two functions in C?

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

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

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

If I were to call the functions on a substantially long array, would these two functions behave differently, would they take more space on the stack?

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

回答by John Bode

First, some standardese:

首先,一些标准

6.7.5.3 Function declarators (including prototypes)
...
7 A declaration of a parameter as ‘‘array of type'' shall be adjusted to ‘‘qualified pointer to type'', where the type qualifiers (if any) are those specified within the [and ]of the array type derivation. If the keyword staticalso appears within the [and ]of the array type derivation, then for each call to the function, the value of the corresponding actual argument shall provide access to the first element of an array with at least as many elements as specified by the size expression.

So, in short, any function parameter declared as T a[]or T a[N]is treated as thoughit were declared T *a.

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

So, why are array parameters treated as though they were declared as pointers? Here's why:

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

6.3.2.1 Lvalues, arrays, and function designators
...
3 Except when it is the operand of the sizeofoperator or the unary &operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type'' is converted to an expression with type ‘‘pointer to type'' that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.

Given the following code:

鉴于以下代码:

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

In the call to foo, the array expression arrisn't an operand of either sizeofor &, so its type is implicitly converted from "10-element array of int" to "pointer to int" according to 6.2.3.1/3. Thus, foowill receive a pointer value, rather than an array value.

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

Because of 6.7.5.3/7, you can write fooas

由于6.7.5.3/7,你可以写foo

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

but it will be interpreted as

但它会被解释为

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

Thus, the two forms are identical.

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

The last sentence in 6.7.5.3/7 was introduced with C99, and basically means that if you have a parameter declaration like

6.7.5.3/7 中的最后一句是用 C99 引入的,基本上意味着如果你有一个像这样的参数声明

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

the actual parameter corresponding to amust be an array with at least10 elements.

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

回答by Thomas Pornin

The difference is purely syntaxic. In C, when the array notation is used for a function parameter, it is automatically transformed into a pointer declaration.

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

回答by caltuntas

No, there is no difference between them. To test I wrote this C code in Dev C++(mingw) compiler:

不,它们之间没有区别。为了测试,我在 Dev C++(mingw) 编译器中编写了这个 C 代码:

#include <stdio.h>

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

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

When I disassemble mainfunction in .exe of both calling versions of binary file in IDA I get exactly the same assembly code like below:

当我在 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

So there is no difference between the two versions of this call, at least the compiler threats them equally.

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