указатели, указывающие на массив целых чисел - PullRequest
5 голосов
/ 20 декабря 2011

Здесь у меня есть сомнения по поводу вывода.

Почему вывод такой же?

   int (*r)[10];
   printf("r=%p  *r=%p\n",r,*r);
   return 0;

Платформа - GCC UBUNTU 10.04

Ответы [ 3 ]

7 голосов
/ 20 декабря 2011

Потому что имя массива распадается на указатель на его первый элемент.

   int (*r)[10]; 

Указатель на массив из 10 целых чисел.
r дает вам сам указатель.

Этот указатель на массив должен быть разыменован для доступа к значению каждого элемента.
Таким образом, вопреки тому, что вы думаете **r, а не *r, вы получаете доступ к первому элементу в массиве.
*r дает вам адрес первого элемента в массиве целых чисел, который совпадает с r

Важно отметить, что:
Массивы не являются указателями

Но выражения, включающие имя массива, иногда ведут себя как указатели, когда те, которые используются в качестве имени массива, не имеют смысла.

4 голосов
/ 20 декабря 2011

Помните, что когда выражение типа "массив N-элементов из T" появляется в большинстве контекстов, оно будет преобразовано в выражение типа "указатель на T", а его значением будет адреспервый элемент в массиве.Исключениями из этого правила являются случаи, когда выражение массива является операндом либо sizeof, либо унарным & (address-of) операндами, либо если выражение массива является строковым литералом, используемым в качестве инициализатора в объявлении массива.

Ваша ситуация является зеркальным отображением следующего:

int a[10] = {0};
printf("a = %p, &a = %p\n", (void *) a, (void *) &a);

В вызове printf выражение a имеет свой тип, преобразованный из "массива из 10 элементов int "to" указатель на int "на основе приведенного выше правила, и его значением будет адрес первого элемента (&a[0]).Выражение &a имеет тип «указатель на массив из 10 элементов int», и его значение будет таким же, как a (адрес первого элемента в массиве совпадает с адресом массивасам).

Ваш код имеет немного неопределенное поведение, так как вы разыменовываете r до того, как он был назначен для указания где-либо значимого, так что вы не можете поверить, что выходные данные вообще точны.Мы можем исправить это так:

int a[10] = {0};
int (*r)[10] = &a;
printf("r = %p, *r = %p\n", (void *) r, (void *) *r);

В этом случае r == &a и *r == a.

Выражение r имеет тип "указатель на массив из 10 элементов с int", а его значением является адрес a.Выражение *r имеет тип "массив из 10 элементов int, который преобразуется в" указатель на int ", а его значение устанавливается на адрес первого элемента, который в данном случае равен a[0]Опять же, значения двух выражений одинаковы.

4 голосов
/ 20 декабря 2011

Вы бы лучше поняли, если бы взглянули на следующую программу.

#include <stdio.h>

int main()
{
    int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int (*r)[10] = &a;

    printf("r=%p  *r=%p  *(r+0)=%p  *(r+1)=%p\n", r, *r, *(r+0), *(r+1));
    printf("sizeof(int)=%d \n", sizeof(int));

    return 0;
}

Вывод выглядит следующим образом:

r=0xbfeaa4b4  *r=0xbfeaa4b4  *(r+0)=0xbfeaa4b4  *(r+1)=0xbfeaa4dc
sizeof(int)=4 

Наблюдения / Точка (и) к сведению:

  • _DO_NOT_ разыменование указателя, который еще не создан, чтобы указывать на адрес. Таким образом, в вашей программе int (*r)[10]; была разыменована без привязки к области памяти. Это не приемлемо.

  • Если вы видите, что вывод - * r совпадает с * (r + 0), что совпадает с r (только в этом случае).

  • Если вы видите выходные данные для * (r + 0) и * (r + 1), это 40 байтов (0xbfeaa4dc - 0xbfeaa4b4 = sizeof (int) * размер массива (который в данном случае равен 10) ). Таким образом, когда вы увеличиваете указатель на определенный тип, он увеличивается до байтов sizeof (типа)!

  • объяснены другие заслуживающие внимания пункты, касающиеся указателя на массив целых чисел здесь

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...