Почему этот код, использующий указатели, не извлекает значение x с помощью b? - PullRequest
2 голосов
/ 28 августа 2011
#include <stdio.h>
int main (){
int x=10,*a=&x;
int *b=(int *)&a;
printf("%d  %d  %d  %d  %d  %d  ",x,a,*a,b,*b,**b);
return 0;
}

В этой маленькой программной переменной x присваивается значение 10, а затем адрес x присваивается переменной указателя a.Теперь правильный путь - int **b=&a, потому что b должен быть указателем на указатель.Но я думал, что это в конечном итоге адрес, который сохраняется.Таким образом, для хранения адреса a с указателем на int b я использую приведение типов int *b=(int *)&a.Теперь адрес a сохранен в b.Поэтому, если я использую *b, это даст тот же результат, что и a.

Но когда я расширю это далее до **b, это не даст тот же результат, что и *a, который я ожидал.На самом деле это дает ошибку.*b и a одинаковы, поэтому, когда я прошу извлечь из этого значения, например **b и *a, это не работает.Для этого я предположил, что *b и a имеют одинаковое значение, но различаются по типу.Значение, заданное a, является указателем, а значение, заданное *b, является целым числом, поэтому **b невозможно, например, *a.

Но я все же думаю, что оно должно работать.

Я использую Dev C ++ 4.9.9.2, который является 32-битным компилятором.Память, выделенная для int и int *, одинакова, то есть 4 байта.И *b и a также имеют одинаковое представление битов.Поэтому, когда я пишу *(*b), я использовал то же значение, что и в *(a).Но что является препятствующим фактором?Формат подобен *(some bit representation), а битовое представление идентично в случае *b и a.Таким образом, значение x должно быть восстановлено.Пожалуйста, объясните фактор предотвращения.

Ответы [ 6 ]

5 голосов
/ 28 августа 2011

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

int main (){
        int x = 10;
        int* a = &x;
        int** b = &a;
        printf("%d  %d  %d  %d  %d  %d  ",x,a,*a,b,*b,**b);
        return 0;
}

Я бы предположил, что проблема в том, что вы объявили b с неправильным типом (а затем ввели &a в этот тип). Это не int*, это int**, то есть указатель на указатель на целое число. Конечно, вы могли бы привести *b к нужному типу в вашем printf() утверждении, но почему бы просто не объявить его правильно с самого начала?

Вот пример идеона: http://ideone.com/idwfd

2 голосов
/ 28 августа 2011
int x= 10;

enter image description here

int *a = &x;    //address of x is 0x33

enter image description here

Int * b = (int *) &a;     //address of a is 0x34

enter image description here

Итак, из вышесказанного имеем:

  • х = 10 а = 33
  • * а = 10 б = 34
  • * b = 33
  • * (int *) * b = 10
  • ** b приведет к ошибке компиляции
1 голос
/ 28 августа 2011

**b будет указывать на правильный блок памяти, но у компилятора нет правильной информации о типе. @Henning говорит, что разыменование b один раз является значением int в соответствии с компилятором, и для типа int нет оператора разыменования. Именно поэтому существует int** и тому подобное: сообщить компилятору, сколько разыменований возможно / необходимо.

Из любопытства, есть ли причина, по которой int* b = a; не работает, если вы хотите получить значение x после одной разыменования?

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

Давайте посмотрим, что здесь происходит.a - указатель на int.Мы берем адрес a, который является указателем на указатель на int, приводим его к указателю на int и присваиваем его b.

Затем мы разыменуем bдважды.b - это указатель на int, поэтому *b - это int.Тогда мы разыменовываем int.Подождите, вы не можете разыменовать int - это не указатель.И вот мы входим в сумеречную зону неопределенного поведения.

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

*b - это целое число, и вы не можете применять унарное * к целому числу.(Как бы компилятор узнал, ожидаете ли вы, что битовый шаблон будет указывать на int, char, short или что-то еще?) Вы можете привести целое число обратно к указателю, а затем присвоить ему значение: *(int*)*b, которое должно делать то, что вы ожидаете.

0 голосов
/ 28 августа 2011
+----------+    +----------+    +----------+
|    10    |    |  addr_x  |    |  addr_a  |
+----------+    +----------+    +----------+
|    x     |    |    a     |    |    b     |
+----------+    +----------+    +----------+
|  addr_x  |    |  addr_a  |    |  addr_b  |
+----------+    +----+-----+    +----+-----+
  ^  ^               |   ^           | 
  |  +----(*a)-------+   +----(*b)---+
  |                                  |
  +----------------(**b)-------------+

Доступ такой же, как и выше.

Вы сказали компилятору, что указатель b является указателем на целое число.Когда вы делаете *b, он обращается к int, и другое косвенное обращение невозможно при типе int and therefore when you access b it as a pointer to a pointer to an integer in (** b ). It is not allowed. To do so you need to typecast the value of b` на правильный тип и используйте его.

Вы хотите использовать значение *b в качестве адреса и получить значение int, хранящееся в расположении адреса *b.Поэтому Вы хотите, чтобы *b был int *, что делает b (int **).Поэтому лучше всего объявить b как int **b;.В вашем случае перед применением типа двойного косвенного обращения b будет int **, а затем используется двойное косвенное указание.

printf ("%x", **((int **)b));

Это будет интерпретировать значение, хранящееся в b, как указатель на указатель нацелое число, а затем получить значение x, как вы хотите.

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