a и & a отличаются для массива, переданного как параметр функции в C - PullRequest
7 голосов
/ 28 февраля 2011

Почему значения a и a отличаются для массива, переданного как параметр функции?b и & b не отличаются для массива, определенного в теле функции.Код следующий:

void foo(int a[2])
{
   int b[2];    
   printf("%p %p\n", a, &a);
   printf("%p %p\n", b, &b);
}

int main()
{
   int a[2];
   foo(a);  
   return 0;
}

РЕДАКТИРОВАТЬ:
Итак, после всего обсуждения, я понимаю, что происходит следующее:

В main():

int a[2]; /* define an array. */
foo(a);   /* 'a' decays into a pointer to a[0] of type (int*). */
          /* since C is pass-by-value, this pointer is replicated and */
          /* a local copy of it is stored on the stack for use by foo(). */

In foo():

printf("%p %p\n", a, &a); /* 'a' is the value of the pointer that has been replicated, */
                          /* and it points to 'a[0]' in main() */
                          /* '&a' is the address of the replicated pointer on the stack. */
                          /* since the stack grows from higher to lower addresses, */
                          /* the value of '&a' is always lower than a. */

Ответы [ 3 ]

10 голосов
/ 28 февраля 2011

Обычно, когда вы набираете void foo( int a[2] ), вы пишете забавным образом void foo( int *a ).

Мне бы пришлось искать конкретную цитату из стандарта, но когда анализируются сигнатуры функций,аргумент типа массив из N элементов типа T преобразуется в указатель на T .При последующем наборе foo(a), a превращается в указатель на адрес первого элемента, который копируется.Внутри foo вы сравниваете значение указателя на первый элемент массива a в main с адресом указателя a в foo.

С другой стороны,в той же функции, когда массив находится в области видимости, как b внутри foo, адрес массива (&b) и адрес первого элемента массива (который может быть получен путем принудительного затухания с помощьюb) - это один и тот же адрес.

Две простые порции информации на будущее:

  • массивы в сигнатурах функций интерпретируются как указатели: избегайте этого синтаксиса и используйте указательсинтаксис, вы получите меньше сюрпризов
  • идентификаторы, которые обозначают распад массива в указатель на первый элемент в большинстве контекстов

Пример:

void foo( int a[2] ); // void foo( int *a );
int main() {
   int x[2];
   foo( x );         // foo( &x[0] ); -- inside foo, a is a copy of &x[0]
   printf( "%d\n%d\n", (int)&a, (int)a ); // &a[0] which is the same address as &a
                                          // (different type though)
}
3 голосов
/ 28 февраля 2011

Массив не является указателем.Он вычисляет указатель почти во всех контекстах, но одним из заметных исключений является оператор &.

Так что если вы вызываете функцию с массивом в качестве параметра

f(a);

a оценивает адрес первого элемента &(a[0]), который передается функции.

Если вы используете &a, то адрес массива берется целиком.Он имеет то же значение, что и &(a[0]), но тип отличается.&(a[0]) имеет тип "указатель на базовый тип" , тогда как &a имеет тип "указатель на массив базового типа" .

Внутри функции &a есть нечторазные.Здесь a - это «указатель на базовый тип» , поэтому &a имеет тип «указатель на указатель на базовый тип» , а адрес, который вы видите, является адресом указателя настек, а не вашего исходного массива.

2 голосов
/ 28 февраля 2011

Когда вы передаете параметр по ссылке в функцию, вы технически помещаете адрес элемента в стек вызовов функций. Когда вы используете & с параметром функции, вы получаете адрес этого значения. Я попытаюсь проиллюстрировать это (все адреса являются произвольными, только для демонстрации):

int main()
{
   int a[2] ; //  a == &a == 0x001234 
   foo(a); // address of a (0x001234) goes to call stack, 
   // this value is stored in 0x00122C 
   // now inside foo(), &a  == 0x00122C , a == 0x001234


}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...