Я новичок в C ++ (и ничего не знаю о C, поскольку имею опыт работы с Java и Python).
Я изучал указатели и запустил следующий код, которым я делюсь с мой файл самоучителя: -

  #include<iostream>
   using namespace std;

    int main(){
        //What is a pointer:-
        // A datatype that holds address of a variable in other datatype
        
        int a=3;
        int* b = &a; //CREATE A POINTER THAT POINTS TO A
                     // '&'STANDS FOR ADDRESS OF OPERATOR
                     // '*' IS CALLED DEREFERNCING OPERATOR
        cout<< b<<endl; //prints address of a
        cout<<&a<<endl; //does the same stuff
        //retreving stored at a particular address
        // '*' GIVES VALUE AT THE ADDRESS STORED IN POINTER
        cout<<*b<<endl;
        cout<<*&a<<endl;
        //pointer to a pointer
        int** c = &b; // pointer to another pointer b
        cout<<"The address of b is"<<c<<endl;
        cout<<"The address of b is"<<&b<<endl;
        cout<<"The value at address c is"<<*c<<endl;
        cout<<"The value at address value stored in c is "<< **c<<endl;
        return 0;
    }

Что вернуло мне следующий результат: -

0x94ac7ff7d4
0x94ac7ff7d4
3
3
The address of b is 0x94ac7ff7c8
The address of b is 0x94ac7ff7c8
The value at address c is 0x94ac7ff7d4
The value at address value stored in c is 3

Любопытство вызвали последние четыре строки вывода. Мы видим, что:-
c указывает на b
а также
b указывает на a

Сами они не являются переменными, тогда почему они не возвращают тот же адрес? Означает ли это, что использование нескольких указателей для одной и той же переменной может занять системные ресурсы, что приведет к плохому дизайну?

-1
Harsh 11 Окт 2021 в 18:05

6 ответов

Лучший ответ

Одна картинка стоит тысячи слов.

   +----------------+
a: |              3 |               94ac7ff7d4
   +----------------+
    ^                              
    |
    `-------------.
                  |
   +--------------|-+
b: | 0x94ac7ff7d4 * |               94ac7ff7d8
   +----------------+
    ^
    |
    `-------------.
                  |
   +--------------|-+
c: | 0x94ac7ff7d8 * |               94ac7ff7dc
   +----------------+

Я думаю о переменной a как о маленьком ящике, в котором может храниться целое число. В C мы знаем его по идентификатору a, но на самом деле на уровне машины компилятор назначил его для размещения по адресу 0x94ac7ff7d4.

Точно так же b - это маленький ящик, который может содержать указатель на целое число, которое обычно реализуется как адрес (число), в котором хранится целое число. Мы знаем его по идентификатору b, но на самом деле компилятор присвоил ему адрес 0x94ac7ff7d8.

Наконец, c - это блок, который может содержать указатель на указатель на целое число, которое снова реализуется как адрес, в котором хранится указатель. Мы знаем его по идентификатору c, и хотя вы этого не сказали, я предполагаю, что компилятор назначил его для размещения по адресу 0x94ac7ff7dc.

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

Для переменной-указателя * дает значение, на которое указывает указатель.

2
Steve Summit 11 Окт 2021 в 15:26

Имейте в виду, что C - язык очень низкого уровня. Многие вещи существуют буквально без хитроумного обращения.

int *b;

B - это переменная, как и любое значение. Он существует по адресу 0x94ac7ff7c8 и содержит значение 0x94ac7ff7d4;

int **c = &b;

c также является переменной. он существует в памяти (по адресу, который не оценивается программой), он содержит значение 0x94ac7ff7c8, которое является тем же значением, что и адрес b.

В отличие от ссылок php, указатели C не будут автоматически указывать на «настоящую» переменную. при этом все, что вы эффективно делаете, - это присвоение значения c, потому что это то, что делает оператор =.

c = 0x94ac7ff7c8;

Следовательно, c и b содержат разные значения.

При оценке "**c" вы спрашиваете:

"Какое значение хранится по адресу c? 0x94ac7ff7c8. Хорошо, тогда какое значение хранится по адресу 0x94ac7ff7c8?" ответ на этот вопрос: **c

Обратите внимание, что следующие строки имеют два разных значения:

int **c = x;
**c = x;

В первом вы объявляете тип с двойным указателем. Звездочки принадлежат выражению int **. Здесь x должен быть типа int **

Во втором вы дважды разыменовываете c. Звездочки принадлежат выражению **c, как в *(*(c)). Здесь x должен быть типа int

Это различие не вызывает двусмысленности, поскольку невозможно разыменовать указатель при его объявлении. У него нет значения, поэтому нет адреса для получения.

1
sybog64 11 Окт 2021 в 15:29

Если вы просто напишете &a, то это не переменная, но как только вы объявите целое число, оно станет переменной с именем b, в которой хранится адрес другой переменной.

0
Vladislav 11 Окт 2021 в 15:10

Переменные, объявленные как указатели, являются объектами типов указателей. Они занимают собственную память.

Итак, эти заявления

int a=3;
int* b = &a;
int** c = &b;

Объявить три разные переменные, хранящие разные значения. Первая переменная имеет тип int и хранит значение 3. Вторая переменная имеет тип int * и хранит адрес первой переменной. Третья переменная имеет тип int ** и хранит адрес второй переменной.

Если у вас есть декларация вроде

T a;

Где T - некоторый спецификатор типа, тогда объявление указателя на эту переменную будет иметь вид

T *p = &a;

Где T, например, может быть int *. В этом случае у вас будет декларация

int * *p = &a;

Или опуская лишние пробелы, это выглядит как

int **p = &a;
0
Vlad from Moscow 11 Окт 2021 в 15:13

Рассмотрим следующий код в свете вашего впечатления "не переменная".

int a = 3;
int b = 4;
int *p = &a;
std::cout << p << " -> " *p << std::endl;
p = &b;
std::cout << p << " -> " *p << std::endl;
```
0
Marshall Clow 11 Окт 2021 в 15:13

Указатель - это такой же объект, как и другие. У него есть тип и значение. Обычно указатель содержит адрес другого объекта, хотя это не делает их такими особенными, как вы думаете.

Учти это:

int a = 0;
int b = 0;
int* p = &a;
p = &b;

int* p = &a; инициализирует p, чтобы указать на a. Значение p - это адрес a. В следующей строке p указывает на b. Теперь значение p - это адрес b. Значение указателей необходимо где-то хранить, как и в случае с int a = 0; значение 0 нужно где-то хранить.

В памяти значения int a и int* p представляют собой просто биты и байты. Только интерпретация как «целое число» или «указывает на целое число» делает указатели особенными.

0
463035818_is_not_a_number 11 Окт 2021 в 15:17