Разница между передачей массива и указателя массива в функцию в C - PullRequest
101 голосов
/ 07 апреля 2011

В чем разница между двумя функциями в C?

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

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

Если бы я вызывал функции из существенно длинного массива, эти две функции вели бы себя по-разному, занимали бы они больше места настек

Ответы [ 3 ]

107 голосов
/ 07 апреля 2011

Сначала немного standardese :

6.7.5.3 Объявление функций (включая прототипы)
...
7 Объявление параметра в виде массива type ’должно быть скорректировано, чтобы указывать квалифицированный указатель на type ’’, где квалификаторы типа (если таковые имеются) - это те, которые указаны в [ и ] вывод типа массива. Если ключевое слово static также присутствует в пределах [ и ] вывод типа массива, затем для каждого вызова функции значение соответствующего фактический аргумент должен обеспечивать доступ к первому элементу массива с как минимум элементы, как указано в выражении размера.

Короче говоря, любой параметр функции, объявленный как T a[] или T a[N], обрабатывается , как если бы было объявлено T *a.

Итак, почему параметры массива обрабатываются так, как если бы они были объявлены как указатели? И вот почему:

6.3.2.1 L-значения, массивы и функциональные обозначения
...
3 За исключением случаев, когда это операнд оператора sizeof или унарный оператор &, или строковый литерал, используемый для инициализации массива, выражение, которое имеет тип ‘‘ array of type ’’ преобразуется в выражение с указателем типа ‘‘ на тип ’, которое указывает на начальный элемент объект массива и не является lvalue. Если объект массива имеет класс хранения регистров, поведение не определено.

С учетом следующего кода:

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

При вызове foo выражение массива arr не является операндом sizeof или &, поэтому его тип неявно преобразуется из "массива из 10 элементов int" в «указатель на 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 элементов.

28 голосов
/ 07 апреля 2011

Разница чисто синтаксическая.В C, когда обозначение массива используется для параметра функции, оно автоматически преобразуется в объявление указателя.

0 голосов
/ 07 апреля 2011

Нет, между ними нет разницы. Для тестирования я написал этот код на C в Dev C ++ (mingw):

#include <stdio.h>

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

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

Когда я разбираю главную функцию в .exe обеих вызывающих версий двоичного файла в IDA, я получаю точно такой же код сборки, как показано ниже:

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

Так что нет никакой разницы между двумя версиями этого вызова, по крайней мере компилятор одинаково угрожает им.

...