Подтвердить что ты не робот

Может ли указатель когда-либо указывать на себя?

Мой вопрос: если переменная-указатель имеет тот же адрес, что и ее значение, действительно ли она указывает на себя?

Например - в следующем фрагменте кода, является указатель на себя? a

#include<stdio.h>

int main(){
   int* a;
   int b = (int)&a;
   a = b;
   printf("address of a = %d\n", &a);
   printf("  value of a = %d\n", a);
}

Если a не является указателем на себя, то снова возникает тот же вопрос: может ли указатель на себя указать?
Кроме того, как полезен самонаправленный указатель?

4b9b3361

Ответ 1

То, что вы на самом деле делаете, - не, указатель указывает на себя. Вы используете пространство памяти, выделенное для указателя, чтобы сохранить местоположение указателя. Указатель на int указывает на ints - никогда другим указателям на ints, включая себя.

Например, предположим, что вы создаете указатель a:

int * a;

Он получает свое место в памяти:

   4     a (5)    6
[....][00000000][....]

В этом простом примере предположим, что a находится в ячейке памяти "5".

Если вы должны это сделать:

a = (int*)&a;

... произойдет следующее:

   4     a (5)    6
[....][00000005][....]

Что здесь происходит, так это то, что a указывает на то, что, по его мнению, является целым числом в местоположении 5. Это также является тем же самым местом памяти, на которое указывает &a, но в контексте того, что a указывает на то, что теперь он указывает на целое число в местоположении 5 - и это целое число равно 5.

Например, оба из них будут работать:

cout<<(int)a;//outputs 5
cout<<*a;//Outputs the integer at memory location 5 - which is 5.

Если вы хотите создать указатель на a, вы определенно можете - любой из этих способов:

int **b = (int**)a;

или

int ** b = &a;



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


Чтобы показать (через еще более простой пример), что происходит, что-то подобное может произойти с int. То есть вы можете сохранить ячейку памяти int внутри себя:

int a=999;

a теперь имеет место в памяти и имеет значение 999 (мы сделаем вид, что оно помещено в ячейку памяти 46):

  45     a (46)   47
[....][00000999][....]

В месте "46" - если бы мы хотели, мы могли бы сохранить это число как целое число в пределах a:

a=(int)&a;

  45     a (46)   47
[....][00000046][....]

а теперь a равен &a по значению, но не в типе - a - это просто целое число, оно не указывает на себя магическим образом только потому, что мы использовали его для хранения своего собственного места памяти.

Ответ 2

void* p = &p;

Это не очень полезно, но структуры, указывающие на себя, полезны в круговых списках длины 1:

typedef struct A {
  struct A* next;
} A;

A a = { &a };

В вашем конкретном примере, я полагаю, вы имели в виду:

int* a;
int b = (int)&a;
a = (int*)b;

// which can be simplified to:
int* a = (int*)&a;

Ответ 3

Адрес памяти в FFFFFFFF может хранить значение FFFFFFFF

Ответ 4

Ну, сначала я бы изменил код:

int **a;
a = (int **)&a;  // otherwise you get a warning, since &a is int ***

Я не уверен, почему вы это сделаете, но это разрешено.

printf("The address of a is %p\n", &a);
printf("a holds the address %p\n", a);
printf("The value at %p is %p\n", a, *a); // the *a is why we made a an int **

Они должны распечатать то же самое.

The address of a is 0x7fffe211d078
a holds the address 0x7fffe211d078
The value at 0x7fffe211d078 is 0x7fffe211d078

Обратите внимание, что это не очень хорошая идея, так как это первая броска a = (int **)&a - это взломать, чтобы заставить a удерживать значение, которое оно не должно удерживать. Вы объявляете его int **, но пытаетесь принудительно вставить в него int ***. Технически размеры одного и того же, но в целом этого не делают, потому что люди ожидают, что int * содержит адрес того, что может использоваться как int, и так далее.

Ответ 5

Да и нет, потому что тип указателя почти так же важен, как и значение указателя.

Да, указатель может содержать позицию указателя на себя; даже длинный может содержать позицию указателя на себя. (Интс обычно может, но я не знаю, гарантировано ли это везде.)

Однако для этого отношения не существует. Если у вас есть указатель, указывающий на себя, у вас на самом деле есть другой тип, когда вы разыгрываете его. Итак:

void *p = &p;
// *p is illegal, even though you probably wanted it to equal 'p'
if( *p != p ) {
    printf("Something wrong");
}

int *i = (int*)&i;
// The following statement is still illegal
if( *i == i ) {
    printf("The universe works!");
}

Я бы сказал, что ответ "нет", потому что он не будет работать, если вы не будете злоупотреблять системой типов. Я считаю это показателем того, что вы делаете что-то неправильно (хотя иногда это обязательно необходимо).

Ответ 6

Выделение указателя приводит к значению его типа значения (например, разыменование int* дает вам тип значения int, int*). Для переменной, указывающей на указатель, ее тип значения должен быть int*, что не соответствует случаю int*, как указано ранее. Поэтому для указателя, указывающего на себя, нужно было бы сделать какой-то бросок, чтобы получить его компилятором:

int* a;
a = reinterpret_cast<int*>(&a);

Чтобы разыскать a, тогда у вас будет int, значением которого является адрес, на котором находится a (усечение мод адреса, соответствующее типу), но оно по-прежнему является int, а не int*, для чего потребуется другой литье.

Указатель на указатель часто известен как дескриптор, который является другим типом (int**), чем указатель (int*). (Обратите внимание, что дескриптор int** имеет тип значения int*.)

Ответ 7

Да, указатель может указать на себя, как указано в ответах.

Возможный случай использования - мы можем использовать этот трюк вместо указателей NULL. Вы можете инициализировать int * p = (int *) & p и проверить это позже, чтобы увидеть, является ли указатель действительным или нет. Это можно было бы использовать, если сказать в системе, где мы хотели, чтобы 0x0 и весь диапазон адресов были действительными адресами.

Вы также можете использовать этот трюк в специальных программах на C, которые не сбой при использовании NULL-указателя, потому что вы избегаете их вообще, а система разыменования не будет разбиваться. Это приведет к ошибочному поведению, но может помочь отладить в определенных ситуациях.

Ответ 8

Да, можно указать на себя.

int* a;
a = &a;

Но не используйте, по крайней мере, так явно.

Ответ 9

Просто:

int *a = (int*)&a;
cout<<"checking: \n"<<&a<<"\n"<<a;

Это указывает на себя.