Ссылочный тип данных: как добраться до безымянного объекта
NULL (nil),
и ее важно не путать с мусором в неинициализированной переменной.
Что это такое
Ссылочный тип - это простой (скалярный) тип данных, значениями которого являются ссылки - адреса памяти, по которым живут другие, динамические объекты определенного типа (его называют указуемым типом). В C такие переменные называются указателями.
Зачем нужен ссылочный тип данных
Вспомните прошлый урок: динамические объекты создаются во время выполнения, и компилятор не может заранее дать им имена. Как обратиться к объекту, у которого нет имени? Только по адресу. Переменные ссылочного типа и хранят эти адреса - а заодно позволяют строить сложные структуры, где объекты ссылаются друг на друга: связные списки, деревья, графы.
Как организовано
- Сама переменная-ссылка - статический объект: она занимает одно машинное слово независимо от того, на насколько большой объект указывает. Доступ по ссылке - O(1).
- Специальное значение NULL (в Паскале - nil) означает "ссылка никуда не указывает". Это осмысленное, законное значение - признак отсутствия связи.
- Совсем другое дело - неопределенное значение: мусор, который лежит в переменной, пока ее не инициализировали. Разыменование такого "указателя в никуда" - классический путь к краху программы.
- Операции над ссылками: присваивание, сравнение на равенство и разыменование - переход от адреса к самому объекту.
a = b копирует только ссылку, а не объект,
поэтому изменение изменяемого объекта видно через оба имени. В C все явно:
звездочка в объявлении, звездочка при разыменовании.
Жизненный цикл ссылки на C
#include <stdio.h>
#include <stdlib.h>
int main(void) {
/* p - переменная ссылочного типа (указатель на int).
Сама она статическая, а указывать будет на динамический объект */
int* p = NULL; /* инициализируем пустой ссылкой */
/* Создаем динамический безымянный объект типа int */
p = (int*)malloc(sizeof(int));
*p = 42; /* разыменование: доступ к объекту по адресу */
printf("Значение: %d, адрес: %p\n", *p, (void*)p);
/* Уничтожаем объект. Ссылка p продолжает существовать,
но теперь указывает в никуда */
free(p);
/* Правило хорошего тона: обнулить ссылку после free */
p = NULL;
return 0;
}
И главная опасность: если перезаписать последнюю ссылку на объект, не вызвав
free, объект останется жить в куче, но добраться до него будет
уже невозможно. Это утечка памяти: программа, которая теряет
ссылки, постепенно съедает всю доступную память.
Коротко: главное
- Ссылочный тип - скалярный тип, значения которого - адреса динамических объектов.
- Динамические объекты безымянны; добраться до них можно только разыменованием ссылки.
- Ссылка занимает одно машинное слово, доступ по ней - O(1).
- NULL - законная пустая ссылка; мусор в неинициализированной переменной - источник крахов.
- Операции: присваивание, сравнение, разыменование; создание - malloc, уничтожение - free.
- Потеря последней ссылки без free - утечка памяти.
Проверьте себя
В функции объявили локальную переменную
int* p; и больше ничего с ней не делали. Что лежит в p?