#c #arrays #pointers
#c #массивы #указатели
Вопрос:
#include <stdio.h>
void main()
{
int a[]={1,2,3,4};
printf("%u %u ",a ,amp;a); //a
printf("%d %d ", *a ,*amp;a); //b
}
В строке ath вывод a
и amp;a
тот же адрес, но в строке bth *amp;a
не дает мне ответа as 1
.
Я знаю, что amp;a
это означает указатель на массив целых чисел, но поскольку адрес тот же, он должен печатать 1
правильно?
Комментарии:
1. Прочитайте раздел 6 comp.lang.c . И
void main()
должно бытьint main(void)
. И ты пропал#include <stdio.h>
.2. Использование
%u
inprintf
для печати значений указателей является неопределенным поведением (и на практике это может легко привести к бессмысленным результатам). Есть%p
специально для печати указателей. И вы должны преобразовать указатели вvoid *
, прежде чем отправлять ихprintf
.
Ответ №1:
a
распадается до указателя на первый элемент массива.
amp;a
является указателем на массив из 4 int
сек.
Несмотря на то, что числовые значения двух указателей одинаковы, указатели не имеют одного и того же типа.
Тип a
(после того, как он распадается на указатель) равен int*
.
Тип amp;a
— это указатель на массив из 4 int
s — int (*)[4]
.
Тип *a
— это an int
.
Тип *amp;a
— это массив из 4 целых int [4]
чисел , который распадается до указателя на первый элемент в вашем выражении.
Вызов
printf("%d %d ", *a ,*amp;a);
эквивалентно:
printf("%d %d ", *a , a);
Кстати, вы должны использовать %p
для указателей. В противном случае вы вызываете неопределенное поведение. Увеличьте уровень предупреждения вашего компилятора, чтобы избежать подобных ошибок.
Ответ №2:
Берем более простую версию вашего кода следующим образом:
#include <stdio.h>
void main()
{
int a[]={1,2,3,4};
printf("%d %d ", *a ,*amp;a); //b
}
Если я скомпилирую этот код, я получу это предупреждение:
test1.c
D:Temptest1.c(7): warning C4477:
'printf' : format string '%d' requires an argument of type 'int', but variadic
argument 2 has type 'int *'
Microsoft (R) Incremental Linker Version 14.00.23506.0
Copyright (C) Microsoft Corporation. All rights reserved.
Это предупреждающее сообщение дает вам причину, по которой это работает не так, как вы ожидаете.
Теперь я могу изменить этот код, чтобы удалить эти предупреждения, и в итоге получаю такой код:
#include <stdio.h>
void main()
{
int a[]={1,2,3,4};
int (*p)[4] = amp;a;
printf("n%u %u ", *a ,*p[0]); //b
}
Этот чистый код компилируется, и при его запуске вы получаете ожидаемый результат:
1 1
Ответ №3:
Последний проект стандарта C предполагает, что
Если операнд является результатом унарного оператора *, ни этот оператор, ни оператор amp; не вычисляются, и результат будет таким, как если бы оба были опущены…
Однако приведенный выше абзац относится к случаю, когда это amp;* , а не *amp; . Попробуйте подумать об этом так:
amp;a // pointer to array[4] of integers
*(amp;a) // array[4] of integers
------------------------------------------
a // array[4] of integers
Обратите внимание, что оператор * удаляет один слой указателей. Следовательно, *(amp;a)
a
семантически идентично. В этом случае a
преобразуется в выражение с типом pointer to an integer
, потому что в другом абзаце предполагается, что
За исключением случаев, когда это операнд оператора sizeof, оператора _Alignof или унарного оператора amp; или строковый литерал, используемый для инициализации массива, выражение, имеющее тип ‘массив типа’, преобразуется в выражение с типом ‘указатель на тип’, который указывает на начальный элементобъекта массива и не является значением lvalue…
В заключение, тот факт, что выводится адрес a
(а не элемент внутри), является естественным.
Ответ №4:
Пожалуйста, сделайте еще одну вещь в своем коде:
printf("%u %u ",a 1 ,amp;a 1); //a1