简体   繁体   English

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

[英]Difference between passing array and array pointer into function in C

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

First, some standardese :首先,一些标准

6.7.5.3 Function declarators (including prototypes) 6.7.5.3 函数声明符(包括原型)
... ...
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. 7 将参数声明为“类型数组”应调整为“类型限定指针”,其中类型限定符(如果有)是在数组类型派生的[]中指定的那些。 If the keyword static also 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. 如果关键字static也出现在数组类型派生的[]中,那么对于函数的每次调用,相应实参的值应提供对数组的第一个元素的访问,该元素至少与指定的元素一样多由大小表达式。

So, in short, any function parameter declared as T a[] or T a[N] is treated as though it 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 6.3.2.1 左值、数组和函数指示符
... ...
3 Except when it is the operand of the sizeof operator 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. 3除了当它是的操作数sizeof操作者或一元&操作者,或是用于初始化数组字符串文字具有类型'类型的数组“”转换到与类型“”指针的表达的表达键入'' 指向数组对象的初始元素并且不是左值。 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 arr isn't an operand of either sizeof or & , so its type is implicitly converted from "10-element array of int " to "pointer to int " according to 6.2.3.1/3.在对foo的调用中,数组表达式arr不是sizeof&的操作数,因此根据 6.2.3.1/3,它的类型从“ int 10 元素数组”隐式转换为“指向int指针”。 Thus, foo will receive a pointer value, rather than an array value.因此, foo将接收一个指针值,而不是一个数组值。

Because of 6.7.5.3/7, you can write foo as因为 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 a must be an array with at least 10 elements. a对应的实参必须是至少10个元素的数组。

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 中,当数组符号用于函数参数时,它会自动转换为指针声明。

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 main function 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.所以这个调用的两个版本没有区别,至少编译器对它们的威胁是平等的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM