где хранится размер переменной указателя? - PullRequest
1 голос
/ 26 августа 2011
 #include <stdio.h>

 int main(void)
 {
int a[5]={1,2,3,4,5};
int *ptr=(int*)(&a+1);
printf("%d %d\n",*(a+1),*(ptr-1));
return 0;
}

выход:

2 5

Здесь в операторе *ptr= (int*)(&a+1) 1 не добавляется &a. На самом деле это как &a + sizeof(a). Теперь мой вопрос: где хранится размер переменной-указателя или, если она не сохраняется, то как она рассчитывается. В случае int, float, char и т. Д. Их размер предопределен в компиляторе, поэтому int *a - это другой случай. Правда ли, что в переменной указателя хранится только адрес? где хранятся метаданные о переменной указателя?

Ответы [ 5 ]

2 голосов
/ 26 августа 2011

Из-за объявления вашей переменной int a[5] = ... компилятор знает, что a имеет тип int [5] (следовательно, sizeof(a) вернет 20).Поскольку компилятор знает тип a, взятие адреса a приведет к указателю правильного типа.Это может быть немного удивительно: &a не дает int**, а скорее int (*)[5] (указатель на массив из пяти целых чисел).

Так что при выполнении

int *ptr=(int*)(&a+1);

Вы берете адрес a, добавляете его (который из-за того, как работает арифметика указателей C / C ++, увеличивает адрес, на который ссылается указатель, на sizeof(a) байт), и затем приводите результат к целому числу.Таким образом, в этот момент ptr указывает за последним элементом массива (со смещением 20).

Затем вы приводите указатель к int* и используете *(ptr-1), поэтому вы разыменовываете значение int всмещение 16 - где находится последний элемент массива.

1 голос
/ 26 августа 2011

Не сохраняется. Компилятору, безусловно, необходимо отслеживать это при компиляции кода, но после этого он в основном просто жестко запрограммирован в сгенерированные инструкции.

0 голосов
/ 26 августа 2011

Указатель - это только адрес памяти, метаданных нет.Добавление N к указателю типа T * приводит к добавлению N * sizeof (T) к значению адреса.Компилятор знает размер каждого типа во время компиляции, ничего не сохраняется.

  • a+1 указывает на второй int в a, потому что он обрабатывает a как int*, то есть указатель напервый элемент, т.е. sizeof (int) добавляется к адресу памяти
  • &a+1 указывает на «второй массив int [5]», т.е. sizeof (int [5]) добавляется к адресу памяти
  • ptr-1 указывает на int прямо перед первым элементом «второго массива», то есть последним элементом.
0 голосов
/ 26 августа 2011

Указатель имеет «двойной тип». С одной стороны, это указатель с собственным размером (скажем, 4 байта для каждого указателя в некоторых системах). С другой стороны, это указатель на то, что имеет размер (кроме void *).

Типы, как правило, напрямую недоступны в C. Вы не можете спросить, "каков тип переменной".

Но размер всегда доступен через sizeof. Таким образом, int * сам может использовать 4 байта, но компилятор знает, что он указывает на целое число, и знает размер целого числа. Для struct xyz * сам указатель может снова составлять 4 байта, но компилятор знает, что он указывает на структуру, и знает размер структуры. Важно то, что указатель имеет тип за пределами «указателя».

Итак, если вы определите struct xyz *ptr, вы всегда можете узнать размер того, на что указывает указатель, проверив sizeof(*ptr). Вы можете сделать это, даже если ptr не инициализирован.

Единственное, что вы не можете сделать, это проверить sizeof(*ptr), когда определено ptr void *.

С точки зрения "метаданных", все это в виде указателя.

0 голосов
/ 26 августа 2011

& имеет тип int (*)[5], то есть & a является указателем на массив , НЕ указателем на int. Компилятор знает (очевидно), каков размер массива, и использует его для арифметики указателей.

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