- •Средства разработки программ на Паскале
- •Структура Паскаль-программы
- •Комментарии
- •Директивы компилятора
- •Идентификаторы
- •Переменные и типы данных
- •Константы
- •Неименованные константы
- •Нетипизированные константы
- •Типизированные константы
- •Простейшие операторы
- •Метки и безусловный переход
- •Ввод и вывод: консоль
- •Ввод с консоли
- •Вывод на консоль
- •Форматный вывод
- •Пример простейшей программы на языке Pascal
- •Типы данных
- •Порядковые типы данных
- •Стандартные подпрограммы, обрабатывающие порядковые типы данных
- •Типы данных, относящиеся к порядковым
- •Вещественные типы данных
- •Конструируемые типы данных
- •Операции и выражения
- •Совместимость типов данных
- •Приведение типов данных
- •Ветвления, массивы, циклы
- •Массивы
- •Операторы циклов
- •Сортировки массивов
- •Быстрая сортировка
- •Символы и строки
- •Неименованные константы
- •Нетипизированные константы
- •Типизированные константы
- •Операции
- •Стандартные функции
- •Стандартные функции и процедуры обработки строк
- •Операции со строками Сравнения
- •Обращение к компонентам строки
- •Конкатенация
- •Множества
- •Описание множеств
- •Множество-константа Неименованная константа
- •Нетипизированная константа
- •Типизированная константа
- •Операции с множествами
- •Представление множеств массивами
- •Представление множеств линейными массивами
- •Представление множеств битовыми массивами
- •Примеры использования символов, строк и множеств
- •Что такое файл
- •Когда нужно использовать файлы
- •Разновидности файлов
- •Описание файлов
- •Текстовые файлы Назначение файла
- •Открытие файла
- •Закрытие файла
- •Считывание из файла
- •Запись в файл
- •Пробельные символы
- •Пример использования файлов
- •Решение
- •Реализация
- •Изменение реакции на ошибку
- •Описание записей
- •Задание записей константой
- •Доступ к полям
- •Оперирование несколькими полями
- •Вложенные операторы with
- •Запись с вариантной частью
- •Описание записи с вариантной частью
- •Механизм использования записи с вариантной частью
- •Бинарные файлы
- •Типизированные файлы
- •Описание типизированных файлов
- •Назначение типизированного файла
- •Открытие и закрытие типизированного файла
- •Считывание из типизированного файла
- •Поиск в типизированном файле
- •Запись в типизированный файл
- •Поиск в нетипизированном файле
- •Запись и чтение
- •Подпрограммы обработки директорий
- •Применимость подпрограмм обработки файлов
- •Процедуры и функции Подпрограммы
- •Список параметров
- •Возвращаемые значения
- •Вызов подпрограмм
- •Способы подстановки аргументов
- •Параметр-значение Описание
- •Механизм передачи значения
- •Параметр-переменная Описание
- •Механизм передачи значения
- •Параметр-константа Описание
- •Механизм передачи значения
- •Области действия имен Разграничение контекстов
- •Побочный эффект
- •Совпадение имен
- •Нетипизированные параметры
- •Явное преобразование типа
- •Совмещение в памяти
- •Открытые параметры
- •Открытые массивы
- •Рекурсивные подпрограммы Динамические структуры данных
- •Операции
- •Очередь
- •Операции
- •Рекурсия
- •Рекурсивные подпрограммы
- •Пример рекурсивного алгоритма
- •Алгоритм решения
- •Стековая организация рекурсии
- •Ограничение глубины рекурсии
- •Замена рекурсивных алгоритмов итеративными
- •Пример сравнения рекурсивного и нерекурсивного алгоритма
- •Рекурсивный алгоритм
- •Реализация рекурсивного алгоритма
- •Полный перебор с отсечением
- •Нерекурсивный алгоритм
- •Реализация нерекурсивного алгоритма
- •Иллюстрация
- •Эффективность
- •Быстрая сортировка2
- •Алгоритм Быстр
- •Реализация алгоритма Быстр
- •Эффективность алгоритма Быстр
- •Адреса и указатели. Списочные структуры данных Статически выделяемая память
- •Разыменование
- •Присваивания
- •Сравнения
- •Динамически распределяемая память
- •Динамическое выделение памяти Типизированные указатели
- •Нетипизированные указатели
- •Динамическое освобождение памяти Типизированные указатели
- •Нетипизированные указатели
- •Списочные структуры
- •Структура списков
- •Описание списков
- •Оперирование элементами списка Хранение списка
- •Обращение к элементам списка
- •Создание списков
- •Просмотр элементов списка
- •Удаление элементов списка
- •Перестройка списков
- •Примеры перестройки линейных списков
- •Реализация
- •Создание дружественного интерфейса
- •Заставка
- •Ввод информации
- •Приглашения
- •Вывод информации
- •Технология программирования и отладка Советы по технологии написания быстро отлаживаемых программ
- •Имена, имена, имена...
- •Кусочки, куски и кусищи...
- •Спасение утопающих - дело рук самих утопающих
- •Отладка и тестирование
- •Поиск и исправление ошибок
- •Правила составления тестов
- •Оптимизация программ
- •Учебники к курсу
Разыменование
Для того чтобы воспользоваться значением, хранящимся по некоторому адресу, необходимо его оттуда "извлечь". Унарная операция ^ называется разыменованием и записывается по следующему шаблону:
<имя_указателя>^
Результатом операции ^ является значение, хранящееся по указанному адресу. Тип этого значения будет определяться типом (типизированного) указателя. К нетипизированным указателям операцию разыменования применять нельзя.
Из-за вольностей, допускаемых процедурой addr(), при разыменовании порой могут возникнуть забавные ситуации. Например, в результате выполнения такой вот программы:
const a: array[1..3] of char ='ААА'; {код(А)=128 или 01000000}
var p: ^word;
begin p:= addr(a);
writeln(p^)
end
на экран будет выведено 32896, что в двоичной системе счисления выглядит как 01000000.01000000 (точкой помечена граница двух байтов). Иными словами, коды двух первых букв оказались слитыми в значение типа word.
Замечание: Операции @ и ^ являются взаимно обратными, то есть для любой переменной a и для любого типизированного указателя p верны следующие равенства:
@(p^)= p и (@a)^ = a
Присваивания
Для указателей действуют гораздо более жесткие правила совместимости типов, чем для обычных переменных. В операции присваивания могут фигурировать только указатели, адресующие переменные одинаковых типов данных. Нельзя, скажем, записать
p:= q; {p: ^integer; q: ^byte}
Обойти эти ограничения позволяет универсальность нетипизированного указателя pointer, совместимого с указателями любых типов:
{p:= ^integer; q: ^byte; t: pointer}
t:= q;
p:= t;
У указателей также существует свой "ноль", который означает, что указатель не указывает никуда:
p:= nil;
Замечание: Если указатель не хранит конкретного адреса (его значение не определено), то это вовсе не означает, что он никуда не указывает. Скорее всего, он все-таки указывает, но только в какую-нибудь неожиданную (хорошо, если не системную) область памяти.
Сравнения
Для указателей определены две операции сравнения: = и <>.
Две переменные, описанные как указатели на один и тот же тип данных, считаются совпадающими, если они указывают на одну и ту же область памяти.
Для разнотипных указателей сравнения невозможны: попытка записать
if p = q then writeln('yes'); {p: ^byte; q: ^integer}
вызовет ошибку уже на этапе компиляции.
Однако сравнивать типизированный и нетипизированный указатели можно.
Динамически распределяемая память
Поскольку к любой переменной можно обратиться двояко - по имени и по адресу, - есть возможность сократить эту избыточность и оставить только один способ. Как мы уже видели, наличие имени означает и наличие адреса. Иными словами, если вы дали переменной имя в разделе var, то в процессе компиляции у нее появится и адрес.
Задумаемся теперь: а если у переменной есть адрес, но нет имени, можно ли оперировать ею с прежней легкостью? Ответ на этот вопрос: "Да, можно!"
Итак, пусть у некоторой переменной нет имени. Тем не менее можно расположить ее в памяти, выделив под нее необходимое количество байтов, и т.д. У переменной будет адрес, будет значение, но не будет имени. Следовательно, обратиться к такой переменной можно будет только с помощью указателя.
"Безымянные" переменные отличаются от "нормальных" переменных:
Нет имени - нечего описывать в разделе var.
Ничего не описано, значит, на этапе компиляции память под переменную не выделена. Следовательно, необходима возможность выделять память (и отменять это выделение) прямо в процессе работы программы. Именно из-за этой гибкости такие переменные и называют динамическими.
Если "потерять" указатель на переменную, то "никто не узнает, где могилка" ее: переменная останется недоступным "мусором", занимая место в памяти, вплоть до конца работы программы.