Перейти к основному содержимому

Указатели

Указатель связывает переменную в памяти с контроллером и роботом

Указатель — одна из самых важных и сложных тем 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, а его разыменовалинет объекта для чтения
указатель вышел за границу массивапрограмма обращается не туда
объект уже исчез, а адрес осталсяадрес больше не действителен

Безопасные привычки

  1. Сразу задавайте указателю адрес или nullptr.
  2. Проверяйте nullptr перед разыменованием.
  3. Для массива храните размер отдельно.
  4. Не используйте адрес после окончания жизни объекта.
  5. В обычных задачах сначала ищите более простой способ без указателей.

Практика

  1. Создайте переменную speed и указатель p на неё.
  2. Выведите значение через speed и через *p.
  3. Измените значение через *p.
  4. Создайте указатель p = nullptr и проверьте его через if.
  5. Создайте массив и выведите первый элемент через указатель.

Проверьте себя

  1. Что хранит указатель?
  2. Что делает & перед именем переменной?
  3. Что делает * перед указателем?
  4. Что означает nullptr?
  5. Почему указатель на массив не хранит размер?
Ориентиры для самопроверки

Сначала ответьте без подсказки. Ответ можно считать полным, если вы:

  • формулируете основную мысль своими словами;
  • называете важные условия, ограничения или меры безопасности;
  • для схемы, кода или расчёта показываете ход решения и ожидаемый результат.

Если один из пунктов объяснить не получается, найдите соответствующую главу статьи, перечитайте её и повторите ответ.

Словарь статьи

ТерминЗначение
адресместо объекта в памяти
указательпеременная, которая хранит адрес
разыменованиеобращение к объекту по адресу
nullptrзначение «нет адреса»
висячий указательуказатель на объект, которого уже нет

Связанные темы

Источники