Mail.ruПочтаМой МирОдноклассникиВКонтактеИгрыЗнакомстваНовостиКалендарьОблакоЗаметкиВсе проекты

Вопрос про указатели в C++

Сергей Соколов Ученик (95), на голосовании 1 месяц назад
Просто проверял кое какие вещи и да, я знаю, как корректно нужно указывать указатель на указатель.
Следующий код:
 #include  
using namespace std;

int main()
{
int a = 5;
int* pa = &a;
int* pa1 = (int*)&pa;
cout << "a: " << a << "\t" << "&a: " << &a << endl;
cout << "pa: " << pa << "\t" << "&pa: " << &pa << "\t" << "*pa: " << *pa << endl;
cout << "pa1: " << pa1 << "\t" << "&pa1: " << &pa1 << "\t" << "*pa1: " << *pa1 << endl;
return 0;
}
Выводит следующее:
 a: 5    &a: 0000000F42AFF584 
pa: 0000000F42AFF584 &pa: 0000000F42AFF5A8 *pa: 5
pa1: 0000000F42AFF5A8 &pa1: 0000000F42AFF5C8 *pa1: 1118827908
Вопрос такой, почему *pa1 равно 1118827908?

Разве *pa1 не должно считать 4 байта 0x00 0x00 0x00 0x0F из адреса &pa и интерпретировать их как int? Потому что в таком случае получается, что это должно быть число 251658240.

Что пошло не так?
Дополнен 2 месяца назад
Также близко 1118827908 в 16ричной системе близко к &pa, но не равно ему в независимости от порядка битов.
1118827908 = 42AFF584
Дополнен 2 месяца назад
Все заметил. Почему-то я перепутал &pa и значение по адресу &pa, а именно &a, которое и дает это число.
Голосование за лучший ответ
Сухачев Мудрец (12960) 2 месяца назад
Вы абсолютно правы, ваш код не работает так, как вы ожидаете. Проблема в том, что вы пытаетесь получить доступ к памяти, которая не предназначена для хранения целого числа.

Объяснение:

int* pa = &a;: Создает указатель pa, который хранит адрес переменной a.
int* pa1 = (int*)&pa;: Создает указатель pa1, который хранит адрес переменной pa. Важно: Этот код делает неявное преобразование типа, что является опасным и может привести к ошибкам. Вы пытаетесь представить адрес указателя pa как адрес целого числа.
Ошибка:

Вы пытаетесь считать 4 байта памяти по адресу &pa как целое число. Однако эта память содержит не данные типа int, а адрес pa, который не является целым числом. Поэтому вы получаете неправильное значение, которое может быть любым.

Правильный способ:

Чтобы получить значение pa через pa1, вам нужно использовать оператор разыменования (*) для pa1:
 #include    

using namespace std;



int main()

{

int a = 5;

int* pa = &a;

int** pa1 = &pa; // Правильный способ объявления указателя на указатель

cout << "a: " << a << "\t" << "&a: " << &a << endl;

cout << "pa: " << pa << "\t" << "&pa: " << &pa << "\t" << "*pa: " << *pa << endl;

cout << "pa1: " << pa1 << "\t" << "&pa1: " << &pa1 << "\t" << "*pa1: " << *pa1 << endl; // Теперь *pa1 - это значение pa

cout << "**pa1: " << **pa1 << endl; // Разменовываем pa1, чтобы получить значение *pa (т.е. значение a)

return 0;

}

Объяснение изменений:

int** pa1 = &pa;: Правильный способ объявления указателя на указатель, теперь pa1 хранит адрес pa.
*pa1: Теперь, после разыменования pa1 мы получаем значение pa, которое является адресом a.
**pa1: Разменовывая pa1 второй раз, мы получаем значение, хранящееся по адресу, на который указывает pa (то есть значение a).
Важные моменты:

Преобразования типов: Избегайте неявных преобразований типов, таких как (int*)&pa, используйте явные преобразования только тогда, когда вы абсолютно уверены, что это необходимо.
Указатели на указатели: Указатели на указатели используются для работы со сложными структурами данных, например, с списками и деревьями.
Память: Важно помнить, что память ограничена, и некорректное использование указателей может привести к ошибкам доступа к памяти и проблемам с безопасностью.
Надеюсь, это пояснение прояснило ситуацию!
Мыслитель (9177) 2 месяца назад
Ботик, уходи
Сергей СоколовУченик (95) 2 месяца назад
Абсолютно не то, что нужно было
робот д24 Мудрец (19569) 2 месяца назад
Pa1 указывает на адрес памяти
Сергей СоколовУченик (95) 2 месяца назад
Да, pa1 является указатель типа int. Соответственно *pa1 должно считать значение по адресу 0000000F42AFF5A8 или тоже самое, что &pa. И потом проинтерпретировать 4 байта 0x00 0x00 0x00 0x0F как int, но это число равно 251658240, а не 1118827908.
робот д24 Мудрец (19569) Сергей Соколов, потому что ты в cout выводишь &pa1 а не *pa1
Jurijus Zaksas Искусственный Интеллект (445767) 2 месяца назад
>Разве *pa1 не должно считать 4 байта
Так оно и читает. Но эти байты 42AFF5A8. Явление сие носит имя little endian и смутило не одного начинающего программиста.
https://en.wikipedia.org/wiki/Endianness
Сергей СоколовУченик (95) 2 месяца назад
Да, я уже в дополнении написал, что заметил. Почему то перепутал, что *pa1 считывает значение не значение по адресу pa, а сам адрес pa. Даже с учетом big/little endian переводил, все равно не билось.
Jurijus Zaksas Искусственный Интеллект (445767) Почему? У тебя 64-битные адреса, значит, в памяти твой адрес записан как F5A842AF000F0000. Читаются первые 4 байта, затем из них делается int, который уже будет 42AFF5A8. Ну или как-то похоже. Сделай указатель на массив байтов и прочитай их по одному - узнаешь, как там точно этот адрес хранится.
Похожие вопросы