“Адрес” (и) массив / адрес того, чтобы быть проигнорированным быть gcc?

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

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.

15
задан dbarbosa 23 May 2010 в 23:51
поделиться

5 ответов

В вашем примере массив test представляет собой блок из 50 целых . Это выглядит так:

| int | int | ... | int |

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

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

Указатель, указывающий на массив из 50 целых чисел, имеет тип int (*) [50 ] - это тип и тест .

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

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

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

24
ответ дан 1 December 2019 в 01:10
поделиться

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

char name[20];

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

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

5
ответ дан 1 December 2019 в 01:10
поделиться

Имя массива, в большинстве случаев вычисляет адрес его начального элемента. Два исключения - это когда это операнд 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
2
ответ дан 1 December 2019 в 01:10
поделиться

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

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

9
ответ дан 1 December 2019 в 01:10
поделиться

Я считаю, что это оптимизация gcc. Думаю об этом.

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

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

-2
ответ дан 1 December 2019 в 01:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: