Указатели

Указатель — одна из самых важных и сложных тем C++. В первых программах можно жить без указателей, но они встречаются в массивах, динамической памяти, драйверах и старых C-интерфейсах.
Указатель хранит адрес. Оператор & берёт адрес переменной. Оператор * позволяет обратиться к значению по адресу.
Адрес переменной
#include <iostream>
using namespace std;
int main() {
int speed = 80;
cout << speed << endl;
cout << &speed << endl;
return 0;
}
Первая строка выводит значение. Вторая строка выводит адрес, по которому переменная лежит в памяти. Точный адрес у всех запусков может быть разным.

Первый указатель
#include <iostream>
using namespace std;
int main() {
int speed = 80;
int* p = &speed;
cout << speed << endl;
cout << *p << endl;
return 0;
}
int* p читается как «указатель на int». В переменной p хранится адрес speed. Запись *p означает «значение по адресу из p».
Изменение через указатель
#include <iostream>
using namespace std;
int main() {
int speed = 80;
int* p = &speed;
*p = 100;
cout << speed << endl;
return 0;
}
Вывод:
100
Мы изменили speed не через имя speed, а через указатель p.
nullptr
Иногда указатель пока никуда не указывает. Для этого используют nullptr.
#include <iostream>
using namespace std;
int main() {
int* p = nullptr;
if (p == nullptr) {
cout << "empty" << endl;
}
return 0;
}
Нельзя писать *p, если p == nullptr. Это попытка обратиться к несуществующему объекту.
Указатель и массив
Имя массива связано с адресом первого элемента.
#include <iostream>
using namespace std;
int main() {
int a[3] = {10, 20, 30};
int* p = a;
cout << *p << endl;
cout << *(p + 1) << endl;
return 0;
}
Вывод:
10
20
Запись p + 1 переходит к следующему элементу массива. Но для начинающего кода обычно понятнее писать a[1].
Ошибки с указателями
| Ошибка | Почему опасно |
|---|---|
| указатель не получил адрес | в нём может быть мусор |
указатель равен nullptr, а его разыменовали | нет объекта для чтения |
| указатель вышел за границу массива | программа обращается не туда |
| объект уже исчез, а адрес остался | адрес больше не действителен |
Безопасные привычки
- Сразу задавайте указателю адрес или
nullptr. - Проверяйте
nullptrперед разыменованием. - Для массива храните размер отдельно.
- Не используйте адрес после окончания жизни объекта.
- В обычных задачах сначала ищите более простой способ без указателей.
Практика
- Создайте переменную
speedи указательpна неё. - Выведите значение через
speedи через*p. - Измените значение через
*p. - Создайте указатель
p = nullptrи проверьте его черезif. - Создайте массив и выведите первый элемент через указатель.
Проверьте себя
- Что хранит указатель?
- Что делает
&перед именем переменной? - Что делает
*перед указателем? - Что означает
nullptr? - Почему указатель на массив не хранит размер?
Сначала ответьте без подсказки. Ответ можно считать полным, если вы:
- формулируете основную мысль своими словами;
- называете важные условия, ограничения или меры безопасности;
- для схемы, кода или расчёта показываете ход решения и ожидаемый результат.
Если один из пунктов объяснить не получается, найдите соответствующую главу статьи, перечитайте её и повторите ответ.
Словарь статьи
| Термин | Значение |
|---|---|
| адрес | место объекта в памяти |
| указатель | переменная, которая хранит адрес |
| разыменование | обращение к объекту по адресу |
nullptr | значение «нет адреса» |
| висячий указатель | указатель на объект, которого уже нет |
Связанные темы
- Массивы — последовательные элементы в памяти.
- Динамические массивы — указатель на память, созданную во время работы.
- Функции — передача данных в подпрограммы.
Источники
- C++ Working Draft. Pointers: https://eel.is/c++draft/dcl.ptr
- Microsoft Learn. Pointers: https://learn.microsoft.com/en-us/cpp/cpp/pointers-cpp