- •Содержание
- •1 Списковые структуры и динамическая память 10
- •2 Списковые структуры и файлы 79
- •3 Мультисписковые структуры 121
- •4 Указатели на функции 134
- •5 Совместное использование указателей на данные и указателей на функции 141
- •6 Оформление курсового проекта 157
- •Введение
- •1Списковые структуры и динамическая память
- •1.1Представления однонаправленных списков массивами указателей на элементы списка
- •1.1.1Представление однонаправленных списков массивами указателей
- •1.1.2Статические массивы указателей
- •1.1.3Операции со списками в статических массивах указателей
- •1.1.4Статические массивы указателей в динамической памяти
- •1.1.5Операции со списками в статических массивах указателей в динамической памяти
- •1.1.6Динамические массивы указателей
- •1.1.7Динамические массивы типизированных указателей
- •1.1.8Операции со списками в динамических массивах типизированных указателей
- •1.1.9Динамические массивы нетипизированных указателей
- •1.1.10Операции со списками в динамических массивах нетипизированных указателей
- •1.1.11Продолжение. Динамические массивы нетипизированных указателей
- •1.1.12Замечания по оператору &
- •1.1.13Нетипизированые указатели и массивы
- •1.1.14Нетипизированые указатели и память
- •1.1.15Продолжение. Динамические массивы нетипизированных указателей
- •2Списковые структуры и файлы
- •2.1Бестиповые файлы и однонаправленные списки на базе массивов указателей на элементы списка
- •2.1.1Представление однонаправленных списков массивами указателей
- •2.1.2Организация файла с однонаправленным списком на базе массивов указателей на элементы списка
- •2.1.3Статические и динамические массивы указателей
- •2.1.4Организация списка дыр
- •2.1.5Функция инициализации файла со списком
- •2.1.6Функция открытия файла со списком
- •2.1.7Функции корректировки указателя на начало списка, заголовка списка дыр, количества элементов списка и текщего размера массива указателей
- •2.1.8Функция выделения записи для нового элемента списка
- •2.1.9Функция освобождения записи удаляемого элемента списка
- •2.1.10 Функция увеличения размера массива указателей на элементы списка
- •2.1.11 Функция вывода содержимого списка
- •2.1.12 Функция поиска элемента списка
- •2.1.13Функция добавления элемента в неотсортированный список
- •2.1.14Функция добавления элемента в отсортированный список
- •2.1.15Функция удаления элемента из отсортированного списка
- •2.1.16Функция удаления списка
- •2.1.17 Функция удаления списка с усечением файла
- •2.1.18 Пример программы обработки отсортированного списка на базе массивов указателей
- •2.1.19Продолжение. Представление однонаправленных списков массивами указателей
- •2.1.20Функция инициализации файла со списком
- •2.1.21Процедура открытия файла со списком
- •2.1.22Процедура корректировки заголовка списка
- •2.1.23 Процедура увеличения размера массива указателей на элементы списка
- •2.1.24Функция поиска элемента списка или позиции вставки нового элемента методом половинного деления
- •2.1.25Функция вывода списка на экран
- •2.1.26Функция добавления нового элемента в отсортированный список
- •2.1.27Функция удаления элемента из отсортированного списка
- •2.1.28Функция удаления списка с усечением файла
- •3Мультисписковые структуры
- •3.1Назначение мультисписков
- •3.2Мультисписки в динамической памяти
- •3.3Мультисписки в бинарных файлах
- •3.4Сохранение и восстановление мультисписка в динамической памяти
- •4Указатели на функции
- •4.1Понятие указателя на функцию и его объявление
- •4.2Переменная-указатель на функцию как параметр другой функции
- •4.3Условия использования указателей на функции
- •4.4Использование указателей на функцию для вызова функций
- •4.4.1Формат переменных-указателей на функцию и бестиповых указателей
- •4.4.2Преобразование переменной-указателя на функцию к бестиповому указателю на функцию
- •4.4.3Вызов функции через бестиповый указатель на функцию
- •4.4.4Преобразование бестипового указателя к переменной типа указатель на функцию
- •4.5Способы вызова функции через указатель на функцию
- •4.5.1Массивы указателей на функции
- •5Совместное использование указателей на данные и указателей на функции
- •5.1Инвариантные функци
- •5.2Функции сравнения
- •5.3Пример 1
- •5.4Пример 2
- •6Оформление курсового проекта
- •6.1Интерфейс программной системы
- •6.2Взаимодействие с мультисписком
- •6.3Отображение содержимого мультисписка
- •6.4Файл справки
- •6.5Документация по курсовому проекту
- •6.5.1Общие положения
- •6.5.2Курсовой проект/работа
- •6.5.3Пояснительная записка
- •6.5.4Техническое задание
- •6.5.5Реферат
- •6.5.6Содержание
- •6.5.7Введение
- •6.5.8 Постановка задачи
- •6.5.9 Анализ решаемой задачи
- •6.5.10Анализ существующих методов организации динамических структур данных
- •6.5.11 Определение путей и методов решения задачи
- •6.5.12Проектирование программы
- •6.5.13Заключение
- •6.5.14Список использованных источников
- •6.6Приложения
1.1.9Динамические массивы нетипизированных указателей
Следующим шагом может быть использование в качестве указателей на элементы списка бестиповых указателей. Это несколько усложнит процесс создания и доступа к конкретному элементу списка, но позволит создавать списки из элементов различных типов и, следовательно, процедуры по работе с такими списками, которые не зависят от типа элемента списка.
Выделение памяти для динамических массивов в этом случае выполняется точно также как и в рассмотренном выше случае динамических массивов с типизированными указателями.
Важно подчеркнуть, что динамические массивы указателей в качестве своих элементов теперь содержат бестиповые указатели.
При выделении в динамической памяти места под элемент списка, в конечном итоге, необходимо получить бестиповый указатель на блок байт, отведенный под этот элемент.
При обращении к элементу списка потребуется преобразование бестипового указателя на элемент списка к типизированному указателю на этот же элемент в соответствии с типом этого элемента.
Для дальнейшего изложения используем следующие типы данных и переменные:
const SizeArrH = 4; //начальный размер массива указателей
const Delta = 3; /*приращение размера массива указателей*/
typedef struct ElmList
{
char Name[30];
int Age;
char Address[30];
} TElmList;
//Переменные :
void* PtrDynArrPtr; /*бестиповый указатель на начало массива указателей*/
int Count; /*реальное количество элементов списка*/
int SizeArr; /*текущий размер массива указателей*/
Динамический массив в динамической памяти - куче (heap), идентифицируется указателем PtrDynArrPtr типа void*, расположенным в статической памяти. Указатель PtrDynArrPtr ссылается на первый байт блока байт, выделенного под этот массив. Все элементы динамического массива располагаются в куче последовательно и по тем же принципам, что и в статической памяти. Поэтому доступ к произвольному элементу динамического массива выполняется в два этапа.
На первом этапе выполняется приведение типа нетипизированного указателя PtrDynArr к типизированому с помощью оператора приведения типа, который имеет следующий вид:
(тип) выражение;
Так как указатель на массив фактически содержит адрес первого элемента массива, который, в свою очередь, является бестиповым указателем на структуру (то есть указатель на бестиповый указатель), то для привидения типа указателя достаточно использовать тип void. Тогда приведение типа для указателя на массив указателей будет иметь вид:
(void**)PtrDynArrPtr
Таким образом, получен доступ к массиву указателей на элементы списка.
На втором этапе выполняется доступ к требуемому элементу массива по его индексу.
-
Динамическая память
Элементы списка
Массив
…
Статическая
указателей
элемент № 1
п амять
на элементы
…
‑> на эл. № 4
элемент № 3
Указатель
‑> на эл. № 3
…
на массив
‑> на эл. № 2
элемент № 4
указателей
‑> на эл. № 1
…
PtrDynArr
элемент № 2
Рисунок 1.15 – Структура списка на базе массива указателей
Примечание. Следует подчеркнуть, что в рассматриваемом случае непосредственно для работы с кучей типизированные указатели не используются. Здесь для работы с кучей используются нетипизированные указатели – указатели типа void*, а это позволяет применять такие указатели к данным любого типа.
Для работы с блоком байт, выделенным под массив, как с набором элементов типа void*, возможен единственный подход:
преобразование беcтипового указателя PtrDynArrPtr к указателю на типизированный указатель –
(void**) PtrDynArrPtr
Обращение к элементу массива указателей на элементы списка. Пусть, например, необходимо получить доступ к элементу массива с индексом 5‑ть. Это выглядит следующим образом:
((void **) PtrDynArrPtr) [5]
После того как был типизирован указатель PtrDynArrPtr, не нужно применять оператор разыменования указателя, так как в языках C и C++ укзатель можно индексировать.
Обращение к элементу списка. Пусть, например, необходимо получить доступ к элементу списка с индексом 5-ть. Это выглядит следующим образом:
*((TElmList*)(((void**)PtrDynArrPtr)[5]))
Здесь сначала выполняется преобразование бестипового указателя PtrDynArrPtr на первый байт блока байт, выделенного для массива указателей, к типизированному указателю на массив бестиповых указателей (void**)PtrDynArrPtr. Затем выполняется доступ к 5‑му элементу массива указателей ((void**)PtrDynArrPtr)[5]. Поскольку элемент массива является бестиповым указателем, то его нужно тоже привести к типу типизированного указателя на элемент структуры
(TElmList*)(((void**)PtrDynArrPtr)[5])
а затем выполняется доступ к соответствующему элементу списка через раскрытие (разыменование) уже полученного типизированного указателя
*((TElmList*)(((void**)PtrDynArrPtr)[5]))
Обращение к конкретному полю элемента списка. Пусть полям Name и Age элемента списка с индексом 5-ть необходимо присвоить некоторое значение. Это выполняется следующим образом:
((TElmList*)(((void**)PtrDynArrPtr )[4]))->Age = 28;
strcpy(((TElmList*)(((void**)PtrDynArrPtr)[4]))->Name, "Пугач");
и, наоборот,
int d=((TElmList*)(((void**)PtrDynArrPtr )[0]))->Age;
char n[30];
strcpy(n,((TElmList*)((( void** )PtrDynArrPtr )[0]))->Name);
Если идет обращение к конкретному полю структуры, то нет необходимости производить разыменование указателя на элемент при помощи оператора "*". Вместо этого, после того как получент доступ к указателю на элемент списка, к нему применяется оператор "->" и указывается название поля. Т.е. через указатель на структуру при помощи оператора "->" получаем доступ к ее полю.
Здесь сначала выполняется преобразование бестипового указателя PtrDynArrPtr на первый байт блока байт, выделенного для массива указателей, к типизированному указателю на массив указателей (void**)PtrDynArrPtr. После чего выполняется раскрытие типизированного указателя на массив указателей и доступ к массиву указателей. Затем выполняется доступ к 5‑му элементу массива указателей ((void**)PtrDynArrPtr)[5], а затем выполняется приведение типа бестипового указателя к указателю на структуру (TElmList*)(((void**)PtrDynArrPtr)[0]), а затем доступ к конкретному полю Name элемента списка ((TElmList*)(((void**)PtrDynArrPtr)[0]))->Name.
Как уже отмечалось, для выделения в куче блока памяти под динамический массив используется оператор new.
указатель = new тип_элемента_массива[размер массива];
Например, необходимо выделить блок для SizeArr элементов типа void*. Это достигается следующим образом:
PtrDynArrPtr = new void*[SizeArr].
Для освобождения блока памяти, отведенного в куче для динамического массива, используется процедура
delete [ ] PtrDynArrPtr.
Автоматически освобождаются участки кучи того же размера, что и резервировались.
Примечание. Если вместо операторов new и delete используются функции malloc и free, то запрос памяти для динамического массива указателей будет иметь вид:
PtrDynArrPtr = malloc( SizeArr * sizeof(void*)),
а освобождение памяти:
free (PtrDynArrPtr).
Для выделения в куче памяти для элемента списка используется оператор new или функция malloc.
void* NPtrElm =new TElmList;
или
void* NPtrElm =malloc( sizeof(TElmList)).
Следует подчеркнуть, что бестиповый указатель NPtrElm затем заносится в соответствующее место в массиве указателей, на который ссылается бестиповый указатель PtrDynArrPtr. Например:
((void**) PtrDynArrPtr) [5] = NPtrElm.
Для освобождения памяти, отведенной в куче для элемента списка, используется оператор delete или функция free(). Пусть бестиповый указатель на удаляемый элемент списка хранится в элементе массива указателей с индексом 5‑ть. Тогда обращение к этим процедурам имеет
void * PtrElmList = ((void**)PtrDynArrPtr)[5];
free(PtrElmList)
или
delete PtrElmList
Примечание. Указанная двухстрочная запись действий по освобождению памяти может быть представлена и в однострочном виде:
delete ((void**)PtrArrPtr)[5];
или
free (((void**)PtrArrPtr)[5]);
