о выражении «& anArray» в c

Во-первых, я прочитал:

  • array
  • &array
  • &array[0]

все будет таким же, пока «массив» – это действительно массив. Поэтому я попробовал:

 int main(){ char ar[]={'a','b','c','\0'}; printf("argument: &ar %s\n",&ar); printf("argument: &ar[1] %s\n",&ar[1]); } 

выход:

 argument:&ar abc argument:&ar[1] bc 

Кажется, что &ar берется как указатель на первый элемент вместо указателя на «ar», который сам является указателем на первый элемент, если я не ошибаюсь.

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

 char a='s'; char *pa=&a; printf("argument: &pa %c\n",&pa); 

Вывод для %c не является даже символом. И не должно быть так, как указатель на первый элемент массива обрабатывается. Я старался:

 char *pa=&ar[0]; char **ppa= &pa; printf("argument: &pa %s\n", ppa); 

Выход для %s , что неудивительно, вздор; но почему это не было бессмыслицей? Ибо, если ar был указателем, он должен быть не столько указателем на указатель, сколько ppa ?

Мои вопросы:

  1. Просто «&» игнорируется при установке перед именем массива? Являются ли имена массивов просто особенными?
  2. Если да, то как компилятор проверяет, что идентификатор, следующий за «&», является ссылкой на массив? Действительно ли он ищет его в списке массивов, поэтому для объявления?

Кажется, что &ar берется как указатель на первый элемент вместо указателя на «ar», который сам является указателем на указатель первого элемента, если я не ошибаюсь.

Вы ошибаетесь. &ar – указатель на массив ar , но массив ar не является указателем какого-либо типа (это массив), поэтому &ar не является указателем на указатель.

Массив является непрерывной последовательностью объектов – в случае ar это непрерывный набор из 4 char . &ar – указатель на этот набор из 4 символов , что обязательно означает, что он указывает то же место, что &ar[0] , указатель на первый char в этом наборе. Он имеет другой тип, однако: &ar имеет тип char (*)[4] что означает «указатель на массив из 4 символов» и &ar[0] имеет тип char * , что означает «указатель на char».

Путаница возникает из-за того, что почти во всех выражениях ar оценивает указатель на первый элемент массива (исключения из этого – это когда операнд унарного оператора или оператора sizeof ). Это не означает, что ar является указателем, хотя – это не так, просто в большинстве случаев он вычисляет значение указателя.

Если ваш код скомпилирован без предупреждений, вы не используете весь свой компилятор. Это поможет вам, если вы попросите его сделать это. Узнайте, как сделать компиляцию с предупреждениями, и узнать, как исправить проблемы, которые он диагностирует. Я скомпилировал код ниже с помощью одной или другой из этих команд:

 gcc -O3 -g -std=c99 -Wall -Wextra -m64 array-stuff.c -o array-stuff gcc -O3 -g -std=c99 -Wall -Wextra -m32 array-stuff.c -o array-stuff 

Это хорошая отправная точка для чистого кода с GCC. Действительно, -Wall без -Wextra тоже неплохо.

Вот адаптация вашего кода (в файле array-stuff.c ) – хотя большая часть его отличается:

 #include  #include  int main(void) { // DC4M = Doesn't compile for me, because I compile with stringent warnings char ar[16] = { 'a', 'b', 'c', '\0' }; // Note explicit size printf("%-18s %s\n", "Code:", "char ar[16] = { 'a', 'b', 'c', '\0' };"); //printf("argument: &ar %s\n", &ar); // DC4M printf("argument: &ar[1] %s\n", &ar[1]); printf("%-18s 0x%" PRIXPTR "\n", "ar:", (uintptr_t)ar); printf("%-18s 0x%" PRIXPTR "\n", "&ar:", (uintptr_t)&ar); printf("%-18s 0x%" PRIXPTR "\n", "(ar+1):", (uintptr_t)(ar+1)); printf("%-18s 0x%" PRIXPTR "\n", "(&ar+1):", (uintptr_t)(&ar+1)); printf("%-18s 0x%" PRIXPTR "\n", "&ar[1]:", (uintptr_t)(&ar[1])); printf("%-18s 0x%" PRIXPTR "\n", "&(ar[1]):", (uintptr_t)(&(ar[1]))); printf("%-18s 0x%" PRIXPTR "\n", "(&ar)[1]:", (uintptr_t)((&ar)[1])); printf("%-18s %zu\n", "sizeof(ar):", sizeof(ar)); printf("%-18s %zu\n", "sizeof(&ar):", sizeof(&ar)); printf("%-18s %zu\n", "sizeof(void*):", sizeof(void*)); printf("%-18s %zu\n", "sizeof(ar[1]):", sizeof(ar[1])); printf("%-18s %zu\n", "sizeof(&ar[1]):", sizeof(&ar[1])); printf("%-18s %zu\n", "sizeof(&(ar[1])):", sizeof(&(ar[1]))); printf("%-18s %zu\n", "sizeof((&ar)[1]):", sizeof((&ar)[1])); { char a = 's'; char *pa = &a; printf("%-18s %s\n", "Code:", "char a = 's';"); printf("%-18s %s\n", "Code:", "char *pa = &a;"); //printf("argument: &pa %c\n", &pa); // DC4M printf("%-18s 0x%" PRIXPTR "\n", "&pa:", (uintptr_t)&pa); printf("%-18s 0x%" PRIXPTR "\n", "&a:", (uintptr_t)&a); printf("%-18s 0x%" PRIXPTR "\n", "pa:", (uintptr_t)pa); } { char *pa = &ar[0]; char **ppa = &pa; //printf("argument: &pa %s\n", ppa); // DC4M printf("%-18s %s\n", "Code:", "char *pa = &ar[0];"); printf("%-18s %s\n", "Code:", "char **ppa = &pa;"); printf("%-18s 0x%" PRIXPTR "\n", "&pa:", (uintptr_t)&pa); printf("%-18s 0x%" PRIXPTR "\n", "ppa:", (uintptr_t)ppa); printf("%-18s 0x%" PRIXPTR "\n", "*ppa:", (uintptr_t)*ppa); printf("%-18s 0x%" PRIXPTR "\n", "&ppa:", (uintptr_t)&ppa); } } 

Это результат работы машины Mac OS X 10.7.4 с 64-разрядной компиляцией:

 Code: char ar[16] = { 'a', 'b', 'c', ' argument: &ar[1] bc ar: 0x7FFF6C9DE570 &ar: 0x7FFF6C9DE570 (ar+1): 0x7FFF6C9DE571 (&ar+1): 0x7FFF6C9DE580 &ar[1]: 0x7FFF6C9DE571 &(ar[1]): 0x7FFF6C9DE571 (&ar)[1]: 0x7FFF6C9DE580 sizeof(ar): 16 sizeof(&ar): 8 sizeof(void*): 8 sizeof(ar[1]): 1 sizeof(&ar[1]): 8 sizeof(&(ar[1])): 8 sizeof((&ar)[1]): 16 Code: char a = 's'; Code: char *pa = &a; &pa: 0x7FFF6C9DE560 &a: 0x7FFF6C9DE56F pa: 0x7FFF6C9DE56F Code: char *pa = &ar[0]; Code: char **ppa = &pa; &pa: 0x7FFF6C9DE558 ppa: 0x7FFF6C9DE558 *ppa: 0x7FFF6C9DE570 &ppa: 0x7FFF6C9DE550 

И это результат 32-разрядной компиляции:

 Code: char ar[16] = { 'a', 'b', 'c', ' argument: &ar[1] bc ar: 0xC008A670 &ar: 0xC008A670 (ar+1): 0xC008A671 (&ar+1): 0xC008A680 &ar[1]: 0xC008A671 &(ar[1]): 0xC008A671 (&ar)[1]: 0xC008A680 sizeof(ar): 16 sizeof(&ar): 4 sizeof(void*): 4 sizeof(ar[1]): 1 sizeof(&ar[1]): 4 sizeof(&(ar[1])): 4 sizeof((&ar)[1]): 16 Code: char a = 's'; Code: char *pa = &a; &pa: 0xC008A668 &a: 0xC008A66F pa: 0xC008A66F Code: char *pa = &ar[0]; Code: char **ppa = &pa; &pa: 0xC008A664 ppa: 0xC008A664 *ppa: 0xC008A670 &ppa: 0xC008A660 

Когда вы понимаете, как поступают различные числа, вы будете хорошо на пути к пониманию вещей.

Обратите внимание, что &array[1] интерпретируется как &(array[1]) ; он отличается от (&array)[1] по типу и размеру. Постфиксные операторы, такие как подстрока массива, связываются более жестко, чем унарные операторы, такие как операторы адреса ( & ) и косвенные ( * ).

Формат printf% s означает «Соответствующий аргумент является указателем на char. Распечатайте строку в этом месте. »И строка для этой цели представляет собой последовательность символов, заканчивающуюся нулевым символом.

Когда вы передали &ar для printf, вы передали адрес «a» (хотя тип не так: printf ожидает указатель на символ, и вы передали указатель на массив из-char, но они имеют тот же адрес), и printf увидел строки ‘a’, ‘b’, ‘c’, ‘\ 0’, поэтому он напечатал «abc». То же самое произошло бы, если вы передали ar или &ar[0] ; они оцениваются по тому же адресу.

Когда вы передали &ar[1] на printf, вы передали указатель туда, где находится «b», а printf увидели строки «b», «c», «\ 0», поэтому он напечатал «bc».

Если вы хотите передать только один символ в местоположении, используйте формат% c и передайте символ (вместо указателя на символ). Например, если вы используете формат% c с *ar , будет напечатан «a», и если вы используете% c с *&ar[1] , будет напечатан «b».

Кажется, что & ar берется как указатель на первый элемент вместо указателя на «ar», который сам является указателем на первый элемент, если я не ошибаюсь.

При использовании в выражении ar действует как указатель на первый элемент массива, такой же как &ar[0] . &ar и ar – одинаковый адрес (первый символ в массиве находится на том же адресе, что и начало массива), хотя они имеют разные типы (указатель на массив символов и указатель на char).

вывод для% c не является даже символом

Это персонаж, а не то, что вы ожидали и, возможно, не обычный или печатный персонаж. % c ожидает, что будет передан аргумент символа, но вы передали ему аргумент адреса.

Если да, то как компилятор проверяет, что идентификатор, следующий за «&», относится к массиву, действительно ли он ищет его в списке массивов, поэтому для объявления?

Разбор сложнее, чем это (по существу, идентификатор идентифицируется как известный массив перед рассмотрением &, тогда вычисляется комбинированное выражение & и идентификатора). Однако эффект заключается в том, что &ar оценивается по тому же адресу, что и первый элемент.