Распределение памяти. Динамическое выделение памяти
Существует два основных способа хранения информации в оперативной памяти: Использование глобальных и локальных переменных. В случае глобальных переменных выделяемые под них поля памяти остаются неизменными на все время выполнения программы. Под локальные переменные программа отводит память из стекового пространства. Однако локальные переменные требуют предварительного определения объема памяти, выделяемой для каждой ситуации. Хотя С++ эффективно реализует такие переменные, они требуют от программиста заранее знать, какое количество памяти необходимо для каждой ситуации. Использование системы динамического распределения. При этом способе память распределяется для информации из свободной области памяти по мере необходимости. Область свободной памяти находится между кодом программы с ее постоянной областью памяти и стеком. Динамическое размещение удобно, когда неизвестно, сколько элементов данных будет обрабатываться.
Пример 1. Демонстрация выполнения операций с динамической памятью.
Функция Прототип и краткое описание mallocvoid * malloc (unsigned s); возвращает указатель на начало области (блока) динамической памяти длинной в s байт. При неудачном завершении возвращает значение NULL. callocvoid * calloc (unsigned n, unsigned m); возвращает указатель на начало области (блока) обнуленной динамической памяти, выделенной для размещения n элементов по m байт каждый. При неудачном завершении возвращает значение NULL. reallocvoid * realloc (void * bl, unsigned ns); изменяет размер блока ранее выделенной динамической памяти до размера ns байт, bl – адрес начала изменяемого блока. Если bl равен NULL (память не выделялась), то функция выполняется как malloc. freevoid * free (void * bl); освобождает ранее выделенный участок (блок) динамической памяти, адрес первого байта которого равен значению bl.
Функции malloc(), calloc() и realloc() динамически выделяют память в соответствии со значениями параметров и возвращают адрес начала выделенного участка памяти. Для универсальности тип возвращаемого значения каждой из этих функций есть void *. Этот указатель можно преобразовать к указателю любого типа с помощью операции явного приведения типа (тип *). Функция free() освобождает память, выделенную перед этим с помощью одной из трех функций malloc(), calloc() или realloc(). Сведения об участке памяти передаются в функцию free() с помощью указателя – параметра типа void *. Преобразование указателя любого типа к типу void * выполняется автоматически, поэтому вместо формального параметра void *bl можно подставить в качестве фактического параметра указатель любого типа без операции явного приведения типов.
Пример 2. Ввести и напечатать в обратном порядке набор вещественных чисел, количество которых заранее не фиксировано, а вводится до начала ввода самих числовых значений.
Каждая компонента любой динамической структуры представляет собой запись, содержащую, по крайней мере, два поля: Поле типа указатель, Поле для размещения данных. В общем случае запись может содержать не один, а несколько указателей и несколько полей данных. Поле данных может быть переменной, массивом или структурой. Для наилучшего представления изобразим отдельную компоненту в виде: где поле Р – указатель; поле D – данные. Элемент динамической структуры состоит из двух полей: информационного поля (поля данных), в котором содержатся те данные, ради которых и создается структура; в общем случае информационное поле само является интегрированной структурой – вектором, массивом, другой динамической структурой и т.п.; адресного поля (поля связок), в котором содержатся один или несколько указателей, связывающий данный элемент с другими элементами структуры;
Данная структура состоит из 4 элементов. Первый элемент имеет поле andmed, равное 73, и связан с помощью своего поля jargmine со вторым элементом, поле andmed которого равно 28, и так далее до последнего, четвертого элемента, поле andmed которого равно 85, а поле jargmine равно NULL, то есть нулевому адресу, что является признаком завершения структуры. Здесь Esim является указателем, который указывает на первый элемент структуры. 73 andmed aadress Esim NULL andmedaadressandmedaadressandmedaadress
struct Solm //объявление типа для объекта «узел» динамической цепочки данных { char *Nimi; int andmed; Solm *jargmine; }; Solm *PSolm; //объявляется указатель PSolm = new Solm; //выделяется память PSolm->Nimi = "STO"; //присваиваются значения PSolm->andmed = 28; PSolm->jargmine = NULL; delete PSolm; // освобождение памяти
Понятие списка хорошо известно из жизненных примеров: список студентов учебной группы, список призёров олимпиады, список (перечень) документов для представления в приёмную комиссию, список почтовой рассылки, список литературы для самостоятельного чтения и т.п. Списком называется упорядоченное множество, состоящее из переменного числа элементов, к которым применимы операции включения, исключения. Список, отражающий отношения соседства между элементами, называется линейным. Длина списка равна числу элементов, содержащихся в списке, список нулевой длины называется пустым списком. Списки представляют собой способ организации структуры данных, при которой элементы некоторого типа образуют цепочку. Для связывания элементов в списке используют систему указателей. В минимальном случае, любой элемент линейного списка имеет один указатель, который указывает на следующий элемент в списке или является пустым указателем, что интерпретируется как конец списка.
Основные операции, производимые со стеком: создание стека; печать (просмотр) стека; добавление элемента в вершину стека; извлечение элемента из вершины стека; проверка пустоты стека; очистка стека.