Что такое имя массива в c?
мне трудно понять тип и использование имени массива в C. Это может показаться длинным сообщением, но, пожалуйста, потерпите со мной.
Я понимаю, что следующее утверждение объявляет a
тип int []
Я.е массива.
int a[30];
пока a
также указывает на первый элемент массива и такие вещи, как *(a+2)
действительны. Таким образом, делая a
выглядеть указатель на целое число. Но на самом деле типы int []
и int*
отличаются; в то время как первый является тип массива и позже указатель на целое число.
также переменная типа int []
преобразуется в переменную типа int*
при передаче его в функции; как в C
массивы передаются по ссылке (за исключением sizeof
оператор).
здесь наступает момент, который заставляет меня мотаться. Взгляните на следующий фрагмент код:
int main()
{
int (*p)[3];
int a[3] = { 5, 4, 6 };
p = &a;
printf("a:%dt&a:%dn",a,&a);
printf("%d",*(*p + 2));
}
выход:
a:2686720 &a:2686720
6
Итак, как работает приведенный выше код? У меня два вопроса:--20-->
-
a
и&a
имеют те же значения. Почему? - что именно
int (*p)[3];
делать? Он объявляет указатель на массив, я знаю это. Но как это указатель на массив отличается от указатель на первый элемент массива и имя массив?
может ли кто-нибудь прояснить ситуацию? У меня чертовски много путаницы.
Я знаю, что я должен использовать %p
в качестве заполнителя вместо использования %d
для печати значения переменных указателя. Поскольку использование целочисленного заполнителя может печатать усеченные адреса. Но я просто хочу, чтобы все было просто.
6 ответов
- a и &A имеют одинаковые значения.Как?
они имеют одинаковое значение, но разные типы. Объекты массива не имеют заполнения между элементами (до или после), Поэтому адрес массива и адрес первого элемента массива одинаковы.
что есть:
(void *) a == (void *) &a
- что именно он делает int (*p)[3]; объявляет указатель на массив,я это знаю.Но,как указатель на массив отличается от указателя на первый элемент массива и имя массива?
это два разных типа указателей. Возьмем, например, арифметику указателя:
a + 1 /* address of the second element of the array */
&a + 1 /* address one past the last element of the array */
EDIT: из-за популярного спроса я добавил ниже некоторую информацию о преобразовании массивов.
за тремя исключениями, в выражении объект типа array of T
преобразуется в значение указателя типа T
указывая на первый элемент массива. Исключения, если объект является операндом sizeof
или &
унарный оператор или если объект является строковым литералом инициализация массива.
например это утверждение:
printf("a:%d\t&a:%d\n", a, &a);
фактически эквивалентно:
printf("a:%d\t&a:%d\n", &a[0], &a);
Также обратите внимание, что d
спецификатор преобразования можно использовать только для печати целого числа со знаком; для печати значения указателя вы должны использовать p
спецификатор (и аргумент должен быть void *
). Поэтому для правильного использования:
printf("a:%p\t&a:%p\n", (void *) a, (void *) &a);
соответственно:
printf("a:%p\t&a:%p\n", (void *) &a[0], (void *) &a);
другие ответы уже объяснил проблему. Я пытаюсь объяснить это какой-то диаграммой. Надеюсь, это поможет.
при объявлении массива
int a[3] = {5, 4, 6}
организация памяти выглядит так:
теперь отвечая на ваш вопрос:
a
и&a
имеют одинаковые значения.Как?
как вы уже знаете, что a
имеет тип массива и имя массива a
становится указателем на первый элемент массива a
(после распада),i.e указывает на адрес 0x100
. Обратите внимание, что 0x100
также является начальным адресом блока памяти (array a
). И вы должны знать, что, в общем, адрес первого байта называется адресом переменной. То есть, если переменная 100 байт, то ее адрес равен адресу первого байта.
&a
- адрес всего блока памяти, i.e это адрес массива a
. См. диаграмму:
теперь вы можете понять, почему a
и &a
оба имеют одинаковое значение адреса, хотя оба имеют разный тип.
что именно он делает
int (*p)[3];
объявляется указатель на массив,я знаю это.Но,как указатель на массив отличается от указателя на первый элемент массива и имя массива?
см. приведенный выше рисунок, ясно объясняется, как указатель на массив отличается от указателя на элемент массива.
При назначении &a
to p
, потом p
указывает на весь массив, имеющий начальный адрес 0x100
.
Примечание: по линии
... как в
C
массивы передаются по ссылкам (за исключением
- a соответствует указателю, указывающему на 0-й элемент массива. В то время как то же самое происходит с &a.Он просто дает начальный адрес массива.
а,a --> pointer pointing to starting element of array a[],it does not know about other element's location.
.
&a --->address location for storing array a[] which stores first element location,but knows every element's location
.
аналогично, расположение других элементов будет (a+2), (a+4) и так до конца массива.
следовательно,вы получили такой результат.
- int (*p)[3] - указатель на массив. если бы это было int * p[3], это означало бы совершенно разный. Это означало бы множество указателей, которые полностью отличались бы от этого контекста.
указатель на массив автоматически позаботится обо всех других элементы в массиве.В этом случае ваш is (p);
тогда как указатель на первый элемент массива, т. е. знаю только о первом элементе массива.Вам придется вручную дайте указателю арифметические направления для доступа к следующим элементам.Смотрите, в этот случай - - - мы можем получить второй элемент из a, добавив 2 к a, т. е. a+2, Третий элемент путем добавления 4 к a, т. е. a+4 и так далее. // виду разность двух, так как это целочисленный массив!
в ответ на вопрос 1, это просто аспект языка C, как разработан, в отличие от большинства других современных языков C/C++ позволяет напрямую манипулировать адресами в памяти и имеет встроенные средства, чтобы "понять", что. Есть много статей в интернете, которые объясняют это лучше, чем я мог бы в этом небольшом пространстве. Здесь один, и я уверен, что есть много других: http://www.cprogramming.com/tutorial/c/lesson8.html
с стандарт C99 n1124 6.3.2.1 p3
за исключением случаев, когда это операнд оператора sizeof или унарный & оператор или строковый литерал, используемый для инициализации массива выражение, имеющее тип " массив типа’, преобразуется в выражение с типом " указатель на тип’, указывающее на начальный элемент объекта array и не является lvalue. Если объект array имеет класс хранения register, поведение не определено.
a и &A имеют одинаковое значение, потому что давным-давно вы должны были использовать оператор адреса & на массивах, чтобы получить адрес массива, но это больше не нужно. Имя массива (в данном случае a) в эти дни просто представляет адрес памяти самого массива, который также является тем, что вы получаете от &a. Это стенография, которую компилятор обрабатывает для вас.