- •Содержание
- •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.13Нетипизированые указатели и массивы
Традиционно предполагается, что массив содержит однотипные элементы. При объявлении массива в статической памяти или при выделении ему места в динамической памяти с помощью оператора new имя массива в статической памяти или соответствующий типизированный указатель на массив в динамической памяти адресуются к первому по порядку элементу массива. При выделении массиву места в динамической памяти и получении адреса в бестиповый указатель, соответствующий указатель на массив в динамической памяти адресуются к первому по порядку байту этого массива.
Однако в практике современного программирования встречаются случаи, когда в одном и том же массиве необходимо хранить разные по смысловому назначению, а может и по типу, элементы. Особенно это характерно для массивов в динамической памяти.
Например, при представлении списка с помощью динамического массива указателей в этом же массиве удобно хранить полезную служебную информацию - реальный размер массива указателей и действительное количество элементов списка. Особенно это удобно когда количество таких списков велико и, тем более, когда заранее неизвестно их возможное количество.
Однако при таком решении приходится специально следить за правильностью обработки начальных элементов массива – элементы с индексами 0 и 1, и остальных элементов массива – элементы с индексами от 2 до М-1. Соответствующее решение показано в предыдущем варианте реализации списка.
Возможность базировать нетипизированный указатель на любую правильно квалифицированную переменную, а, следовательно, и на элемент массива позволяет представить такой массив следующим образом:
|
|
индекс |
|
|
M-3 |
|
Незанятая часть массива |
… |
|
|
N+2 |
|
Указатель N -> |
N+1 |
|
Указатель N -> |
N-1 |
|
|
|
|
Указатель 2 -> |
+1 |
PtrV -> |
Указатель 1 -> |
0 |
|
Количество элементов в списке N |
-1 |
PtrBase -> |
Размер массива М |
-2 |
Рисунок 1.18 – Структура массива указателей, содержащего служебную информацию с индексацией указателей начиная с нуля.
Рассмотрим реализацию предложенного решения для статического массива и динамических массивов, создаваемых с помощью оператора new .
typedef struct ElmList
{
char Name[30];
int Age;
char Address[30];
} TRec;
Объявление переменных:
TRec Rec;
TRec ArrRec[5];
TRec* TpPtrDynArrRecBase; /*типизированный указатель на начало массива записей*/
void* NTPtrDynArrRecBase; /*бестиповый указатель на фактиче-
ское начало массива записей*/
void* NTPtrArrRecV; /*бестиповый указатель на условное нача
ло массива записей*/
void* Ptr;
void* NTPtrList;
TRec* PtrRec; /*типизированный указатель на запись*/
int Base, J, K;
/* I. Работа с указателем на элемент массива ArrRec в статической памяти*/
/*Пример с использованием индексации указателя*/
/*NTPtrArrRecV базируется на элемент внутри статического массива с индексом Base, а позиция Base может рассматриваться как "нулевая" позиция в массиве. Теперь можно выбирать элементы массива:
-сверху от "нулевой" позиции по индексу K, где K = 1, 2, и т.д.
-снизу от "нулевой" позиции по индексу K, где K = -1, -2 и т.д.*/
Base = 2; /*базовый индекс - "нулевая" позиция в массиве*/
NTPtrArrRecV = &ArrRec[Base]; /*нетипизированный указатель на эле- мент массива*/
K = 0; /*индекс элемента массива*/
listBox1->Items->Add(System::String::Concat(S"Base = ", Convert::ToString(Base), S"K=0" )); /*Вывод в listBox базового индекса и индекса
рассматриваемого элемента относительно базового*/
/*Перевод строки char[] в строку System::String*/
String* S1;
S1 = __gc new String((((TRec*)NTPtrArrRecV)[K]).Name);
listBox1->Items->Add(S1); /*Вывод в listBox поля Name К-го элемента
массива относительно базового*/
K = -1;
listBox1->Items->Add(System::String::Concat(S"Base = ", Convert::ToString(Base), S"K =- 1" )); /*Вывод в listBox базового индекса и индекса
рассматриваемого элемента относительно базового*/
S1 = (((TRec*)NTPtrArrRecV)[K]).Name; /*Вывод в listBox поля Name К-го
элемента массива относительно базового*/
listBox1->Items->Add(S1);
K = +1;
listBox1->Items->Add(System::String::Concat(S"Base = ", Convert:: ToString(Base), S"K=+1" )); /*Вывод в listBox базового индекса и индекса
рассматриваемого элемента относительно базового*/
S1 = (((TRec*)NTPtrArrRecV)[K]).Name; /*Вывод в listBox поля Name К-го
элемента массива относительно базового*/
listBox1->Items->Add(S1);
В языках C/C++, как известно, существуют два способа обращения к элементам массива: по индексу и использование адресной арифметики. Первый способ был рассмотрен выше. В настоящий момент более широко используется второй способ доступа к элементам массива.
int m[10];
int * p;
Для того, чтобы получить доступ к 4-му элементу массива нужно выполнить один из двух операторов:
m[3]; /*В языке C++ индексация массива начинается с нуля, поэтому четвертый элемент массива имеет индекс 3*/
или
*(p+3); /* p содержит адрес первого элемента массива типа int, при
увеличении указателя на 1 – получим адрес следующего
элемента базавого типа(в данном случае int), следовательно
оператор (p+3) вернет указатель на четвертый элемент мас-
сива. В таком случае значение p не меняется*/
Для того, чтобы получить доступ к следующему элементу массива, нужно выполнить оператор:
*(++p) /*Здесь указатель сначала получает адрес следующего
элемента массива, а затем с помощью оператора разымено
вания обращамся к этому элементу. Значение p изменилось*/
Аналогично следующие операторы позволяют получить доступ к предыдущему элементу массива:
*(p-1); или *(--p).
/*Пример работы со статическим массивом записей с использо
ванием адресной арифметики*/
/*NTPtrArrRecV базируется на элемент внутри статического массива с индексом Base, а позиция Base может рассматриваться как "нулевая" позиция в массиве. Теперь можно выбирать элементы массива:
-сверху от "базовой" позиции по индексу K, где K = 1, 2, и т.д.
-снизу от "базовой" позиции по индексу K, где K = -1, -2 и т.д.*/
Base = 2; /*базовый индекс - "нулевая" позиция в массиве*/
NTPtrArrRecV = &ArrRec[Base]; /*нетипизированный указатель на элемент
массива*/
K = 0; /*индекс элемента массива*/
listBox1->Items->Add(System::String::Concat(S"Base = ", Convert:: ToString (Base) , S"K=0" ));
String* S1;
S1 = __gc new String(((TRec*)NTPtrArrRecV)->Name); /*Доступ к 0-му элементу
относительно «базы» и перевод
его поля Name в строку типа System::String */
listBox1->Items->Add(S1); /*Вывод 0-го элемента в listBox*/
K = -1;
listBox1->Items->Add(System::String::Concat(S"Base = ", Convert:: ToString (Base) , S"K=-1" ));
S1 = (((TRec*)NTPtrArrRecV) – 1 )->Name; /*Доступ к -1 -му элементу относительно
«базы» и перевод егополя Name в строку типа System::String*/
listBox1->Items->Add(S1); /*Вывод -1 -го элемента в listBox*/
K = +1;
listBox1->Items->Add(System::String::Concat(S"Base = ", Convert:: ToString (Base), S"K=+1" ));
S1 = (((TRec*)NTPtrArrRecV)+1)->Name; /*Доступ к +1 -му элементу относительно
«базы» и перевод его поля Name в строку типа System::String*/
listBox1->Items->Add(S1); /*Вывод +1 -го элемента в listBox*/
/* II. Работа с указателем на элемент массива в динамической памяти*/
/*1. Случай создания динамического массива и работа с типизированным указателем на массив*/
TpPtrDynArrRecBase = new TRec[20]; /*выделение места под массив*/
/*NTPtrArrRecV базируется на элемент внутри динамического массива с индексом Base а позиция Base может рассматриваться как "нулевая" позиция в массиве. Теперь можно выбирать элементы массива:
снизу от "нулевой" позиции по индексу K, где K = -1, -2 и т.д.
сверху от "нулевой" позиции по индексу K, где K = 1, 2, и т.д.*/
Base = 2; /*базовый индекс - "нулевая" позиция в массиве*/
NTPtrArrRecV = & TpPtrDynArrRecBase[Base];
K = 0;
listBox1->Items->Add(System::String::Concat(S"Base = ", Convert:: ToString (Base), S"K=0" ));
String* S1;
S1 = __gc new String(((TRec*)NTPtrArrRecV)[0].Name); /*Доступ к 0-му элементу
относительно «базы» и перевод его поля Name в
строку типа System::String */
listBox1->Items->Add(S1); /*Вывод 0-го элемента в listBox*/
K = -1;
listBox1->Items->Add(System::String::Concat(S"Base = ", Convert:: To-
String (Base) , S"K=-1" )); /*Вывод в listBox базового индекса и
индекса рассматриваемого элемента относительно базового*/
S1 = (((TRec*)NTPtrArrRecV)[K]).Name; /*Вывод в listBox поля Name К-го
элемента массива относительно базового*/
listBox1->Items->Add(S1);
K = +1;
listBox1->Items->Add(System::String::Concat(S"Base = ", Convert::ToString(Base),
S"K=+1" )); /*Вывод в listBox базового индекса и индекса
рассматриваемого элемента относительно базового*/
S1 = (((TRec*)NTPtrArrRecV)[K]).Name; /*Вывод в listBox поля Name К-го
элемента массива относительно базового*/
listBox1->Items->Add(S1);
/* 2. Случай создания динамического массива и работа с помощью нетипизированного указателя на массив указателей*/
NtPtrDynArrRecBase = new TRec[20]; /*выделение места под массив*/
/* NtPtrDynArrRecBase – нетипизированный указатель*/
/*NTPtrArrRecV базируется на элемент с индексом Base внутри динамического массива, а позиция Base может рассматриваться как "нулевая" позиция в массиве. Теперь можно выбирать элементы массива:
снизу от "нулевой" позиции по индексу K, где K = -1, -2 и т.д.
сверху от "нулевой" позиции по индексу K, где K = 1, 2, и т.д.*/
Base = 2; /*базовый индекс - "нулевая" позиция в массиве*/
NTPtrArrRecV = &((TRec*)NTPtrDynArrRecBase)[Base];
/*Остальные операции по выводу 0-го, -1 – го и +1 – го элементов
массива на экран аналогичны случаю 1, описанному выше.*/
Следует обратить внимание на несколько моментов:
Тип всех элементов массива в статической памяти и в динамической памяти, при его создании оператором new, - один и тот же. Однако обращаясь к одному или группе смежных элементов массива через указатели разных типов можно по-разному обрабатывать эти элементы.
Ответственность за выход за пределы массива несет программист. Транслятор в языке C++ не выполняет такой контроль.
