1. Основы указателей: адреса, разыменование, типы
Основы указателей: адреса, разыменование, типы
Зачем в C нужны указатели
Указатели — это механизм языка C, который позволяет:
> «C provides a number of operators to specify the address of an object and to access the value of an object through its address.» — cppreference: Pointer
В этой статье мы разберём базу: что такое адрес, как объявлять указатели, как получать адрес и как разыменовывать указатель.
Память и адреса: что хранится в переменной и что в указателе
Выполняющаяся программа использует память. Каждая переменная в памяти размещается по некоторому адресу.
int x).Важно:
!Диаграмма показывает, что указатель хранит адрес переменной и позволяет обратиться к её значению.
Объявление указателей и типы
Как объявляется указатель
Указатель объявляется с помощью * рядом с именем (или типом):
Это читается как: p — указатель на int.
Эквивалентные по смыслу варианты записи:
Рекомендация по стилю (чтобы меньше ошибаться): ставить * рядом с именем:
Потому что запись ниже часто вводит в заблуждение:
Тип указателя — это часть контракта
Тип указателя говорит компилятору две ключевые вещи:
Примеры типов указателей:
| Запись | Смысл | Что лежит по адресу |
|---|---|---|
| int *p | указатель на int | целое типа int |
| double *pd | указатель на double | число типа double |
| char *s | указатель на char | символ (часто первый символ строки) |
| void *vp | указатель на «неизвестно что» | тип не определён, разыменовывать нельзя без приведения |
Оператор * в объявлении и в выражении — это разные роли
Символ * встречается в двух местах, и его легко перепутать:
int *p; он означает, что p — указатель.p он означает разыменование* (доступ к значению по адресу).Контекст решает всё.
Получение адреса: оператор &
Чтобы получить адрес переменной, используется оператор & (address-of):
Здесь:
x — обычная переменная типа int.&x — адрес переменной x, тип выражения &x будет int *.p хранит адрес x.Частые замечания:
& в C также бывает побитовым И (a & b), но это другой оператор и другой контекст.Разыменование: оператор *
Если указатель хранит корректный адрес, то можно получить или изменить значение по этому адресу через *.
Прочитать значение по адресу
*p читается как: «значение, на которое указывает p».
Изменить значение по адресу
Здесь меняется не p, а содержимое памяти по адресу, который хранится в p.
Нулевой указатель: NULL
Иногда нужно значение «ни на что не указывает». Для этого используют нулевой указатель.
Обычно применяют NULL из стандартных заголовков:
Правило безопасности:
NULL нельзя: *p при p == NULL приводит к неопределённому поведению.Проверка перед использованием:
void *: универсальный указатель и его ограничения
void * может хранить адрес объекта любого типа, но компилятор не знает, что лежит по этому адресу.
Пример:
Важно:
void * напрямую, потому что неизвестно, сколько байт и как интерпретировать.Константность и указатели: минимальная база
Ключевое различие:
| Запись | Что запрещено |
|---|---|
| const int p | нельзя менять p, но можно менять p |
| int const p = &x; | нельзя менять p, но можно менять p |
Пример для const int *p:
Эта тема будет регулярно встречаться дальше, особенно при работе со строками и API.
Мини-словарь терминов
*p).NULL).Типичные ошибки новичков
p и *p: первый — адрес, второй — значение по адресу.NULL.int* p, q;.void * без приведения.Что дальше
В следующих статьях курса мы используем базу из этой темы, чтобы уверенно: