В следующем фрагменте кода значения указателя и адреса указателя отличаются, как и ожидалось.
Но значения массива и адреса не имеют!
Как это может быть?
Вывод
my_array = 0022FF00
&my_array = 0022FF00
pointer_to_array = 0022FF00
&pointer_to_array = 0022FEFC
#include <stdio.h>
int main()
{
char my_array[100] = "some cool string";
printf("my_array = %p\n", my_array);
printf("&my_array = %p\n", &my_array);
char *pointer_to_array = my_array;
printf("pointer_to_array = %p\n", pointer_to_array);
printf("&pointer_to_array = %p\n", &pointer_to_array);
printf("Press ENTER to continue...\n");
getchar();
return 0;
}
sizeof(&array)
возвращает?Ответы:
Имя массива обычно вычисляется в адрес первого элемента массива, так
array
и&array
имеет одинаковое значение (но различные типов, такarray+1
и&array+1
будет не быть равными , если массив больше , чем 1 элемент длиной).Есть два исключения к этому: когда имя массива является операндом
sizeof
или унарным&
(адресом), имя относится к самому объекту массива. Таким образом,sizeof array
вы получите размер в байтах всего массива, а не размер указателя.Для массива, определенного как
T array[size]
, он будет иметь типT *
. Когда / если вы увеличиваете его, вы переходите к следующему элементу в массиве.&array
вычисляется по тому же адресу, но с учетом того же определения создает указатель типаT(*)[size]
- т. е. это указатель на массив, а не на один элемент. Если вы увеличите этот указатель, он добавит размер всего массива, а не размер одного элемента. Например, с таким кодом:Мы можем ожидать, что второй указатель будет на 16 больше первого (потому что это массив из 16 символов). Поскольку% p обычно преобразует указатели в шестнадцатеричное, это может выглядеть примерно так:
источник
&array
указатель на первый элемент массива, где asarray
ссылается на весь массив. Принципиальное различие также можно наблюдать, сравниваяsizeof(array)
, сsizeof(&array)
. Однако обратите внимание, что если вы передаетеarray
в качестве аргумента функции,&array
фактически передается только. Вы не можете передать массив по значению, если он не инкапсулирован вstruct
.&array[0]
передается по указателю на свой первый элемент , а не&array
по указателю на массив. Это может быть придиркой, но я думаю, что это важно прояснить; Компиляторы будут предупреждать, если функция имеет прототип, который соответствует типу переданного указателя.int *p = array; int **pp = &p;
.Это потому, что имя массива (
my_array
) отличается от указателя на массив. Это псевдоним адреса массива, а его адрес определяется как адрес самого массива.Однако указатель является обычной переменной C в стеке. Таким образом, вы можете взять его адрес и получить другое значение от адреса, который он содержит внутри.
Я писал об этой теме здесь - пожалуйста, посмотрите.
источник
register
) независимо от продолжительности хранения: статической, динамической или автоматической.my_array
сам находится в стеке, потому чтоmy_array
это весь массив.my_array
Если объект не является оператором&
илиsizeof
, вычисляется указатель на его первый элемент (т. е.&my_array[0]
), но онmy_array
сам не является указателем (my_array
по-прежнему является массивом). Этот указатель - просто эфемерное значение (например, данныйint a;
, он похожa + 1
) - концептуально, по крайней мере, он «вычисляется по мере необходимости». Реальное «значение»my_array
- это содержимое всего массива - просто закрепление этого значения в C похоже на попытку уловить туман в банке.В C, когда вы используете имя массива в выражении (включая передачу его в функцию), если только оно не является операндом
&
оператора address-of ( ) илиsizeof
оператора, оно распадается на указатель на свой первый элемент.То есть в большинстве контекстов
array
эквивалентно&array[0]
как по типу, так и по значению.В вашем примере
my_array
имеет тип,char[100]
который уменьшается до a,char*
когда вы передаете его в printf.&my_array
имеет типchar (*)[100]
(указатель на массив из 100char
). Поскольку это операнд&
, это один из случаев, когдаmy_array
не сразу затухает указатель на его первый элемент.Указатель на массив имеет то же значение адреса, что и указатель на первый элемент массива, поскольку объект массива представляет собой просто непрерывную последовательность его элементов, но указатель на массив имеет тип, отличный от указателя на элемент этот массив. Это важно, когда вы выполняете арифметику указателей для двух типов указателей.
pointer_to_array
имеет типchar *
- инициализируется, чтобы указывать на первый элемент массива, как это происходитmy_array
в выражении инициализатора, - и&pointer_to_array
имеет типchar **
(указатель на указатель на achar
).Из них:
my_array
(после распада наchar*
),&my_array
иpointer_to_array
все они указывают непосредственно на массив или на первый элемент массива и поэтому имеют одинаковое значение адреса.источник
Причину
my_array
и&my_array
результат в одном и том же адресе можно легко понять, если взглянуть на структуру памяти массива.Допустим, у вас есть массив из 10 символов (вместо 100 в вашем коде).
Память для
my_array
выглядит примерно так:В C / C ++ массив распадается на указатель на первый элемент в выражении, таком как
Если вы посмотрите, где находится первый элемент массива, вы увидите, что его адрес совпадает с адресом массива:
источник
В языке программирования B, который был непосредственным предшественником C, указатели и целые числа были свободно взаимозаменяемыми. Система будет вести себя так, как будто вся память представляет собой гигантский массив. С каждым именем переменной связан либо глобальный, либо относящийся к стеку адрес, для каждого имени переменной единственное, что должен отслеживать компилятор, это глобальная или локальная переменная и его адрес относительно первой глобальной или локальной переменной. переменная.
Учитывая глобальное заявление , как
i;
[не было никакой необходимости указывать тип, так как все было целое / указатель] будет обрабатываться компилятором как:address_of_i = next_global++; memory[address_of_i] = 0;
и заявление , какi++
будет обрабатываться как:memory[address_of_i] = memory[address_of_i]+1;
.Декларация вроде
arr[10];
бы будет обработана какaddress_of_arr = next_global; memory[next_global] = next_global; next_global += 10;
. Обратите внимание, что как только это объявление было обработано, компилятор мог сразу забыть о том,arr
что он является массивом . Заявление вродеarr[i]=6;
бы будет обработано какmemory[memory[address_of_a] + memory[address_of_i]] = 6;
. Компилятору было бы все равно,arr
представлены ли массив иi
целое число, или наоборот. Действительно, было бы все равно, если бы они были массивами или обоими целыми числами; он с удовольствием сгенерирует код, как описано, независимо от того, будет ли полученное поведение полезным.Одна из целей языка программирования C состояла в том, чтобы быть в значительной степени совместимым с B. В B имя массива [называемое "вектором" в терминологии B] идентифицировало переменную, содержащую указатель, который первоначально был назначен для указания на к первому элементу выделения заданного размера, поэтому, если это имя появилось в списке аргументов для функции, функция получит указатель на вектор. Несмотря на то, что C добавил «реальные» типы массивов, чье имя было жестко связано с адресом выделения, а не с переменной-указателем, которая первоначально указывала бы на выделение, наличие массивов, разлагаемых на созданный указателями код, объявивший массив типа C, ведет себя идентично в код B, который объявил вектор, а затем никогда не изменял переменную, содержащую ее адрес.
источник
На самом деле,
&myarray
иmyarray
оба являются базовым адресом.Если вы хотите увидеть разницу вместо использования
использование
источник