
- •Содержание
- •Введение
- •1. Cтруктуры данных и алгоритмы
- •1.1. Понятие структур данных и алгоритмов
- •1.2. Информация и ее представление в памяти
- •1.2.1. Природа информации
- •1.2.2. Хранение информации
- •1.3. Системы счисления
- •1.3.1. Непозиционные системы счисления
- •1.3.2. Позиционные системы счисления
- •1.3.3. Изображение чисел в позиционной системе счисления
- •1.3.4. Перевод чисел из одной системы счисления в другую
- •1.4. Классификация структур данных
- •1.5. Операции над структурами данных
- •1.6. Структурность данных и технология программирования
- •2. Простые структуры данных
- •2.1. Числовые типы
- •2.1.1. Целые типы
- •2.1.2. Вещественные типы
- •1). Число 15.375;
- •2). Десятичное число 0.0375;
- •3). Десятичное число 2.5;
- •4). Значения верхней и нижней границ диапазона положительных чисел:
- •1). Число -15.375;
- •2). Число 1.0;
- •3). Значения верхней и нижней границ диапазона положительных чисел
- •2.1.3. Десятичные типы
- •2.1.4. Операции над числовыми типами
- •2.2. Битовые типы
- •2.3. Логический тип
- •2.4. Символьный тип
- •2.5. Перечислимый тип
- •2.6. Интервальный тип
- •2.7. Указатели
- •2.7.1. Физическая структура указателя
- •2.7.2. Представление указателей в языках программирования
- •2.7.3. Операции над указателями.
- •3. Статические структуры данных
- •3.1. Векторы
- •3.2. Массивы
- •3.2.1. Логическая структура
- •3.2.2. Физическая структура
- •3.2.3. Операции
- •3.2.4. Адресация элементов с помощью векторов Айлиффа
- •3.2.5. Специальные массивы
- •3.3. Множества
- •3.3.1. Числовые множества
- •3.3.2. Символьные множества
- •3.3.3. Множество из элементов перечислимого типа
- •3.3.4. Множество от интервального типа
- •3.3.5. Операции над множествами
- •3.4. Записи
- •3.4.1. Логическое и машинное представление записей
- •3.4.2. Операции над записями
- •3.5. Записи с вариантами
- •3.6. Таблицы
- •3.7. Операции логического уровня над статическими структурами. Поиск
- •3.7.1. Последовательный или линейный поиск
- •3.7.2. Бинарный поиск
- •3.8. Операции логического уровня над статическими структурами. Сортировка
- •3.8.1. Сортировки выборкой
- •3.8.2. Сортировки включением
- •3.8.3. Сортировки распределением.
- •3.8.4. Сортировки слиянием.
- •4. Полустатические структуры данных
- •4.1. Характерные особенности полустатических структур
- •4.2. Стеки
- •4.2.1. Логическая структура стека
- •4.2.2. Машинное представление стека и реализация операций
- •4.2.3. Стеки в вычислительных системах
- •4.3. Очереди fifo
- •4.3.1. Логическая структура очереди
- •4.3.2. Машинное представление очереди fifo и реализация операций
- •4.3.3. Очереди с приоритетами
- •4.3.4. Очереди в вычислительных системах
- •4.4. Деки
- •4.4.1. Логическая структура дека
- •4.4.2. Деки в вычислительных системах
- •4.5. Строки
- •4.5.1. Логическая структура строки
- •4.5.2. Операции над строками
- •4.5.3. Представление строк в памяти.
- •5. Динамические структуры данных. Связные списки
- •5.1. Связное представление данных в памяти
- •5.2. Связные линейные списки
- •5.2.1. Машинное представление связных линейных списков
- •5.2.2. Реализация операций над связными линейными списками
- •5.2.3. Применение линейных списков
- •5.3. Мультисписки
- •5.4. Нелинейные разветвленные списки
- •5.4.1. Основные понятия
- •5.4.2. Представление списковых структур в памяти.
- •5.4.3. Операции обработки списков
- •5.5. Язык программирования lisp
- •5.6. Управление динамически выделяемой памятью
- •6. Нелинейные структуры данных
- •6.1.Графы
- •6.1.1. Логическая структура, определения
- •6.1.2. Машинное представление оpгpафов
- •6.2. Деревья
- •6.2.1. Основные определения
- •6.2.2. Логическое представление и изображение деревьев.
- •6.2.3. Бинарные деревья.
- •6.2.4. Представление любого дерева, леса бинарными деревьями.
- •6.2.5. Машинное представление деревьев в памяти эвм.
- •6.2.6. Основные операции над деревьями.
- •6.2.7. Приложения деревьев.
- •6.2.8 Деревья Хаффмена (деревья минимального кодирования)
- •6.2.9 Деревья при работе с арифметическими выражениями
- •6.2.10 Формирование таблиц символов.
- •6.2.11 Сбалансированные деревья
2.7.2. Представление указателей в языках программирования
В программе на языке высокого уровня указатели могут быть типизированными и нетипизированными. При объявлении типизированного указателя определяется и тип объекта в памяти, адресуемого этим указателем. Так например, объявления в языке PASCAL:
Var ipt : ^integer; cpt : ^char;
или в языке C:
int *ipt; char *cpt;
означают, что переменная ipt представляет собой адрес области памяти, в которой хранится целое число, а cpt - адрес области памяти, в которой хранится символ. Хотя физическая структура адреса не зависит от типа и значения данных, хранящихся по этому адресу, компилятор считает указатели ipt и cpt имеющими разный тип, и в Pascal оператор:
cpt := ipt;
будет расценен компилятором как ошибочный (компилятор C для аналогичного оператора присваивания ограничится предупреждением). Таким образом, когда речь идет об указателях типизированных, правильнее говорить не о едином типе данных "указатель", а о целом семействе типов: "указатель на целое", "указатель на символ" и т.д. Могут быть указатели и на более сложные, интегрированные структуры данных, и указатели на указатели.
Нетипизированный указатель - тип pointer в Pascal или void * в C - служит для представления адреса, по которому содержатся данные неизвестного типа. Работа с нетипизированными указателями существенно ограничена, они могут использоваться только для сохранения адреса, обращение по адресу, задаваемому нетипизированным указателем, невозможно.
2.7.3. Операции над указателями.
Основными операциями, в которых участвуют указатели являются присваивание, получение адреса, выборка.
Присваивание является двухместной операцией, оба операнда которой - указатели. Как и для других типов, операция присваивания копирует значение одного указателя в другой, в результате оба указателя будут содержать один и тот же адрес памяти. Если оба указателя, участвующие в операции присваивания типизированные, то оба они должны указывать на объекты одного и того же типа.
Операция получения адреса - одноместная, ее операнд может иметь любой тип, результатом является типизированный (в соответствии с типом операнда) указатель, содержащий адрес объекта-операнда.
Операция выборки - одноместная, ее операндом является типизированный (обязательно!) указатель, результат - данные, выбранные из памяти по адресу, заданному операндом. Тип результата определяется типом указателя-операнда.
Перечисленных операций достаточно для решения задач прикладного программирования поэтому набор операций над указателями, допустимых в языке Pascal, этим и ограничивается. Системное программирование требует более гибкой работы с адресами, поэтому в языке C доступны также операции адресной арифметики, которые описываются ниже.
К указателю можно прибавить целое число или вычесть из него целое число. Поскольку память имеет линейную структуру, прибавление к адресу числа даст нам адрес области памяти, смещенной на это число байт (или других единиц измерения) относительно исходного адреса. Результат операций "указатель + целое", "указатель - целое" имеет тип "указатель".
Можно вычесть один указатель из другого (оба указателя-операнда при этом должны иметь одинаковый тип). Результат такого вычитания будет иметь тип целого числа со знаком. Его значение показывает на сколько байт (или других единиц измерения) один адрес отстоит от другого в памяти.
Отметим, что сложение указателей не имеет смысла. Поскольку программа разрабатывается в относительных адресах и при разных своих выполнениях может размещаться в разных областях памяти, сумма двух адресов в программе будет давать разные результаты при разных выполнениях. Смещение же объектов внутри программы друг относительно друга не зависит от адреса загрузки программы, поэ- тому результат операции вычитания указателей будет постоянным, и такая операция является допустимой.
Операции адресной арифметики выполняются только над типизированными указателями. Единицей измерения в адресной арифметике является размер объекта, который указателем адресуется. Так, если переменная ipt определена как указатель на целое число (int *ipt), то выражение ipt+1 даст адрес, больший не на 1, а на количество байт в целом числе (в MS DOS - 2). Вычитание указателей также дает в результате не количество байт, а количество объектов данного типа, помещающихся в памяти между двумя адресами. Это справедливо как для указателей на простые типы, так и для указателей на сложные объекты, размеры которых составляют десятки, сотни и более байт.
В связи с имеющимися в языке C расширенными средствами работы с указателями, следует упомянуть и о разных представлениях указателей в этом языке. В C указатели любого типа могут быть ближними (near) и дальними (far) или (huge). Эта дифференциация связана с физической структурой адреса в i8086, которая была рассмотрена выше. Ближние указатели представляют собой смещение в текущем сегменте, для представления такого указателя достаточно одного 16-разрядного слова. Дальние указатели представляются двумя 16-разрядными словами - сегментом и смещением. Разница между far или huge указателями состоит в том, что для первых адресная арифметика работает только со смещением, не затрагивая сегментную часть адреса, таким образом, операции адресной арифметики могут изменять адрес в диапазоне не более 64 Кбайт; для вторых - в адресной арифметике участвует и сегментная часть, таким образом, предел изменения адреса - 1 Мбайт.
Впрочем, это различие в представлении указателей имеется только в системах программирования, работающих в среде MS DOS, в современных же операционных системах, поддерживающих виртуальную адресацию, различий между указателями нет, все указатели можно считать гигантскими.