"Address of" (&) массив / адрес игнорируемого быть gcc? - PullRequest
14 голосов
/ 24 мая 2010

Я преподаватель начального курса программирования, и некоторые студенты допустили такой тип ошибки:

char name[20];
scanf("%s",&name);

, что неудивительно, поскольку они учатся ... Что удивительно, так это то, что, кроме предупреждения gcc, код работает (по крайней мере, эта часть). Я пытался понять, и я написал следующий код:

void foo(int *v1, int *v2) {
  if (v1 == v2)
    printf("Both pointers are the same\n");
  else
    printf("They are not the same\n");
}

int main() {
  int test[50];
  foo(&test, test);
  if (&test == test)
    printf("Both pointers are the same\n");
  else
    printf("They are not the same\n");
}

Компиляция и выполнение:

$ gcc test.c -g
test.c: In function ‘main’:
test.c:12: warning: passing argument 1 of ‘foo’ from incompatible pointer type
test.c:13: warning: comparison of distinct pointer types lacks a cast
$ ./a.out 
Both pointers are the same
Both pointers are the same

Кто-нибудь может объяснить, почему они не отличаются?

Я подозреваю, что это потому, что я не могу получить адрес массива (поскольку у меня не может быть & &x), но в этом случае код не должен компилироваться.

Редактировать: Я знаю, что массив сам по себе совпадает с адресом первого элемента, но я думаю, что это не связано с этой проблемой. Например:

int main() {
  int a[50];
  int * p = a;
  printf("%d %d %d\n", p == a, p == &a[0], &p[0] == a);
  printf("%d %d %d\n", p == &a, &p == a, &p == &a);
}

печать:

$ ./a.out 
1 1 1
1 0 0

Я не понимаю, почему вторая строка начинается с 1.

Ответы [ 5 ]

23 голосов
/ 24 мая 2010

В вашем примере массив test представляет собой блок 50 ints. Так это выглядит так:

| int | int | ... | int |

Когда вы применяете унарный оператор & к массиву, вы получаете адрес массива . Точно так же, как когда вы применяете это к чему-либо еще, действительно. Таким образом, &test является указателем, который указывает на этот блок 50 ints:

(&test) -----------> | int | int | ... | int |

Указатель, который указывает на массив из 50 дюймов, имеет тип int (*)[50] - это тип &test.

Когда вы просто используете имя test в любом месте, где оно не является операндом операторов sizeof или унарных - &, оно оценивается как указатель на его первый элемент. Таким образом, test, который вы передаете foo(), оценивается как указатель на элемент test[0]:

(test) -----------------\
                        v
(&test) -----------> | int | int | ... | int |

Вы можете видеть, что оба они указывают на один и тот же адрес - хотя &test указывает на весь массив, а test указывает на первый элемент массива (который отображается только в другом * 1029). * типы , которые имеют эти значения).

9 голосов
/ 24 мая 2010

На самом деле они разные, по крайней мере, они не одного типа.

Но в C адрес массива совпадает с адресом первый элемент в массиве, поэтому «они не отличаются», в основном, они указывают на одно и то же.

5 голосов
/ 24 мая 2010

Если вы определяете массив как

char name[20];

name, то он неявно преобразуется в char*, но &name имеет тип char (*)[20] (указатель на массив из 20 символов),Адреса совпадают.

Проверьте адрес (&name + 1).Он отличается от &name на sizeof(char [20]).

2 голосов
/ 24 мая 2010

Имя массива, в большинстве случаев оценивает по адресу его начального элемента.Два исключения: когда это операнд sizeof или унарный &.

Унарный & дает адрес своего аргумента.Адрес массива совпадает с адресом его начального элемента, поэтому (void*)&array == (void*)array всегда будет истинным.

array при преобразовании в указатель на его начальный элемент имеет тип T *.Тип &array равен T (*)[n], где n - количество элементов в массиве.Таким образом,

int* p = array;        // Works; p is a pointer to array[0]
int* q = &array;       // Doesn't work; &array has type int (*)[10]
int (*r)[10] = &array; // Works; r is a pointer to array
0 голосов
/ 24 мая 2010

Я считаю, что это оптимизация gcc.Подумайте об этом.

  • &test указывает на адрес test
  • test указывает на первый элемент test или &test[0]
  • [0] совпадает (по большей части) с *

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

...