Ссылочный тип данных: как добраться до безымянного объекта

Модуль "Объекты и ссылки" • урок 2 из 7 • ~7 минут

Суть урока. Ссылочный тип - скалярный тип, значения которого - адреса (ссылки) на безымянные динамические объекты. Доступ к объекту - через операцию разыменования. Сама ссылка занимает одно машинное слово, пустая ссылка - NULL (nil), и ее важно не путать с мусором в неинициализированной переменной.
Ссылочный тип данных: переменная, хранящая адрес памяти
Переменная ссылочного типа и специальное значение NULL

Что это такое

Ссылочный тип - это простой (скалярный) тип данных, значениями которого являются ссылки - адреса памяти, по которым живут другие, динамические объекты определенного типа (его называют указуемым типом). В C такие переменные называются указателями.

Зачем нужен ссылочный тип данных

Вспомните прошлый урок: динамические объекты создаются во время выполнения, и компилятор не может заранее дать им имена. Как обратиться к объекту, у которого нет имени? Только по адресу. Переменные ссылочного типа и хранят эти адреса - а заодно позволяют строить сложные структуры, где объекты ссылаются друг на друга: связные списки, деревья, графы.

Как организовано

А как в Python? В Python вы не работаете со ссылочным типом напрямую, потому что там все переменные - неявные ссылки на объекты. Присваивание 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?

Как вам урок? Спасибо за отзыв!