
- •6.050201 «Системная инженерия»
- •Донецк, 2012
- •1 Цели и задачи дисциплины
- •2 Теоретические основы программирования
- •2.1 Основные сведения в области информатики Общее понятие алгоритма
- •Алгоритмические языки
- •Типы переменных
- •Целочисленные переменные
- •Кольцо вычетов по модулю m
- •Интерпретация положительных и отрицательных чисел
- •Вещественные переменные
- •Машинный эпсилон
- •Запись вещественных констант
- •Символьные переменные
- •Логические переменные и выражения
- •Массивы
- •Текстовые строки
- •Оперативная память
- •Процессор
- •Cisc и risc-процессоры
- •Алгоритм работы компьютера
- •Аппаратный стек
- •Команды вызова подпрограммы call и возврата return
- •Аппаратный стек и локальные переменные подпрограммы
- •2.2. Стандарты построения блок-схем алгоритмов
- •4 Компиляция и выполнение программ
- •5 Структурное программирование
- •5.1 Описание переменных
- •Константы
- •Целые числа
- •Вещественные числа
- •Логические величины
- •Символы и байты
- •Кодировка, многобайтовые символы
- •5.2 Основные операции и их приоритет
- •Порядок вычисления выражений
- •5.3 Операторы
- •Операторы цикла
- •5.4 Организация ввода-вывода
- •Манипуляторы и форматирование ввода-вывода
- •Строковые потоки
- •Ввод-вывод файлов
- •5.5 Массивы
- •5.6. Указатели и операции над ними
- •5.7 Ссылки
- •5.8 Динамическое выделение памяти
- •5.9 Функции
- •Подставляемые функции
- •Имена функций
- •Необязательные аргументы функций
- •Рекурсия
- •Назначение шаблонов
- •Функции-шаблоны
- •5.10 Область видимости имен
- •5.11 Сложные структуры данных
- •5.11.1 Структуры
- •5.11.2 Перечисления
- •5.11.3. Объединения
- •5.12. Динамические структуры данных
- •6 Препроцессор
- •Определение макросов
- •Условная компиляция
- •Дополнительные директивы препроцессора
- •7 Объектно-ориентированное программирование
- •7.1 Основные понятия объектно-ориентированного программирования
- •Определение методов класса
- •Виртуальные методы
- •Виртуальные методы и переопределение методов
- •Преобразование базового и производного классов
- •Внутреннее и защищенное наследование
- •Абстрактные классы
- •Множественное наследование
- •Виртуальное наследование
- •Интерфейс и состояние объекта
- •Объявление friend
- •7.2 Конструктор и деструктор класса
- •Копирующий конструктор
- •Деструкторы
- •Инициализация объектов
- •Операции new и delete
- •7.3 Перегрузка операций
- •Как определять операции
- •Преобразования типов
- •Явные преобразования типов
- •Стандартные преобразования типов
- •Преобразования указателей и ссылок
- •Преобразования типов, определенных в программе
- •7.4 Использование включаемых файлов
- •7.5. Шаблоны классов
- •"Интеллигентный указатель"
- •Задание свойств класса
- •8 Обработка исключительных ситуаций
- •Примеры обработки исключительных ситуаций
- •Список использованных источников
5.11.3. Объединения
Особым видом структур данных является объединение. Определение объединения напоминает определение структуры, только вместо ключевого слова struct используется union. В отличие от структуры, все атрибуты объединения располагаются по одному адресу. Под объединение выделяется столько памяти, сколько нужно для хранения наибольшего атрибута объединения. Объединения применяются в тех случаях, когда в один момент времени используется только один атрибут объединения и, прежде всего, для экономии памяти. Предположим, нам нужно определить структуру, которая хранит "универсальное" число, т.е. число одного из предопределенных типов, и признак типа. Это можно сделать следующим образом:
struct Value {
enum NumberType { ShortType, LongType,
DoubleType };
NumberType type;
short sx; // если type равен ShortType
long lx; // если type равен LongType
double dx; // если type равен DoubleType
};
Атрибут type содержит тип хранимого числа, а соответствующий атрибут структуры – значение числа.
Value shortVal;
shortVal.type = Value::ShortType;
shortVal.sx = 15;
Хотя память выделяется под все три атрибута sx, lx и dx, реально используется только один из них. Сэкономить память можно, используя объединение:
struct Value {
enum NumberType { ShortType, LongType,
DoubleType };
NumberType type;
union number {
short sx; // если type равен ShortType
long lx; // если type равен LongType
double dx; // если type равен DoubleType
} val;
};
Теперь память выделена только для максимального из этих трех атрибутов (в данном случае dx). Однако и обращаться с объединением надо осторожно. Поскольку все три атрибута делят одну и ту же область памяти, изменение одного из них означает изменение всех остальных. На рисунке поясняется выделение памяти под объединение. В обоих случаях мы предполагаем, что структура расположена по адресу 1000. Объединение располагает все три своих атрибута по одному и тому же адресу.
Рис. 5.3 – Использование памяти в объединениях.
Замечание. Объединения существовали в языке Си, откуда без изменений и перешли в Си++. Использование наследования классов, позволяет во многих случаях добиться того же эффекта без использования объединений, причем программа будет более надежной.
5.12. Динамические структуры данных
Очень часто в задачах программирования заранее неизвестно, какой объем данных необходимо будет обрабатывать. Применение динамических массивов позволяет только частично решить эту проблему, поскольку при выделении памяти под массив необходимо уже знать его размерность, а также потому, что память, выделенная для массива, может долго пустовать в ожидании ввода всех данных. Кроме того, под массив память выделяется единым блоком и не всегда в таком виде в достаточном объеме компьютер может ее найти. Поэтому были предложены динамические структуры данных, в которых для каждого элемента память можно выделять по мере необходимости.
К динамическим структурам данных относятся различные виды списков. Обычно элемент списка содержит смысловую часть (собственно хранимые данные) и ссылку на другой или другие элементы списка. Для программирования списков используют структуры или классы. Различают односвязные списки, двусвязные списки и деревья.
В односвязном списке каждый элемент хранит адрес распложения следующего элемента. Последний элемент в качестве адреса следующего элемента хранит NULL. Выделяется специальная адресная константа, хранящая адрес первого элемента списка (принято называть ее head). Передвижение по списку начинается всегда с первого элемента, а затем происходят переходы по цепочке к каждому следующему элементу. Двигаться в таком списке можно только от головы к хвосту. Добавление элементов возможно в любое место списка. Оно реализуется по принципу вставки звена в цепь. Цепь размыкается и новое звено связывается с предыдущим и последующим элементом.
Для облегчения передвижения по списку ввели двусвязные списки. В таком списке в элементе хранится не только адрес следующего элемента, но и адрес предыдущего элемента (адреса соседей по цепочке). Благодаря этому двигаться в таком списке можно не только вперед, но и назад. В дополнение к указателю на голову списка, вводится указатель на его конец (хвост или tail).
В дереве каждый элемент (узел) хранит ссылки на адреса своих потомков. Наибольшее распространение получили бинарные деревья, в которых у каждого узла не более двух потомков (левый и правый), хотя можно создавать деревья произвольной структуры. Работа с деревьями похожа на работу с односвязными списками (движение начинается с начала, от корня), но усложняется наличием нескольких дочерних узлов.
Списки получили значительное распространение при работе с данными.