- •Министерство образования и науки российской федерации
- •Начальный курс программирования на основе алгоритмического языка Паскаль
- •Введение
- •Часть. Основы программирования на Паскале
- •1.1. Структура простейшей Паскаль-программы
- •1.2. Данные и операции над ними
- •1.2.1. Свойства ячейки памяти. Переменные и константы
- •1.2.2. Типы данных
- •1.2.3. Правила записи констант
- •1.2.4. Описание переменных и именованных констант в Паскале
- •1.2.5. Выражения
- •1.3. Операторы преобразования данных
- •1.3.1. Оператор присваивания
- •1.3.2. Понятие ввода и вывода
- •1.3.3. Оператор вывода
- •1.3.4. Оператор ввода
- •1.4. Разработка простейших программ
- •1.4.1. Понятие о качестве программы и основные технологические принципы разработки программ
- •1.4.2. Алгоритм и способы его записи.
- •1.4.3. Изображение алгоритмов в виде блок-схем
- •1.4.4. Базовые структуры алгоритмов и их кодирование на Паскале
- •1. Следование
- •2. Ветвление (развилка)
- •If условие then
- •If условие then
- •3. Цикл
- •1.4.5. Примеры разработки программ
- •1.5. Массивы
- •1.5.1. Понятие массива. Основные правила работы с массивами в Паскале
- •1.5.2. Примеры программ с массивами
- •1.614. Структура паскаль-программы
- •Часть.Подпрограммы
- •2.1. Общие сведения о подпрограммах
- •2.2. Процедуры в Паскале
- •2.2.1.Описание процедур
- •2.2.2. Обращение к процедуре
- •2.3. Функции Паскаля
- •2.3.1. Описание функций
- •2.3.2. Обращение к функции
- •2.4. Глобальные и локальные имена
- •2.5. Использование подпрограммы в качестве параметра другой подпрограммы
- •2.6. Модули
- •2.6.1. Общие сведения
- •2.6.2. Структура модуля
- •2.6.3. Использование модулей
- •2.6.4. Модули как средство программирования
- •Часть. Обработка символьной информации и документов сложной структуры
- •3.1. Обработка символьной информации
- •3.1.1. Символьный тип
- •3.1.2.Строковые типы
- •3.1.3. Подпрограммы, работающие со строками
- •Функции
- •Процедуры
- •3.2. Тип запись
- •3.3. Файлы
- •3.3.1. Общие понятия
- •3.3.2. Файлы в Турбо Паскале
- •3.3.3. Текстовые файлы
- •Пример 1
- •Пример 2
- •3.3.4. Типизированные файлы
- •3.3.5. Нетипизированные файлы
- •Часть IV. Работа с динамическими массивами
- •О статическом и динамическом распределении памяти
- •Указатели в Паскале
- •Динамические массивы
- •Формальные параметры-массивы без указания границ
- •Приложение 1. Краткая инструкция по работе в среде Turbo (Borland) Pascal.
- •Режимы компиляции программы, использующей модули
- •Приложение 2. Краткая инструкция по работе в режиме консольного приложения средыDelphi. Создание консольного приложения
- •Сохранение консольного приложения.
- •Отладка программы
- •Контрольные вопросы
- •Заключение
- •Библиографические ссылки
- •Содержание
- •Часть IV. Работа с динамическими массивами 98
Указатели в Паскале
Указатели в рассматриваемых версиях Паскаля могут быть типированными или нетипированными. Типированные указатели хранят адрес ячейки данных заявленного типа, для нетипированных указателей тип содержимого не задается.
Указатели описываются с помощью инструкций:
имя_типированного_указателя: ^тип_содержимого_ячейки;
имя_нетипированного_указателя: pointer;
В качестве типа содержимого ячейки (базового типа) может быть использован любой стандартный тип или имя нестандартного типа.
Указателю может быть присвоено значение другого указателя, причем в операторе присваивания (слева и справа от знака:=) должны участвовать указатели с одинаковым базовым типом или один из указателей должен быть нетипированным.
Допустимо сравнивать указатели одного типа на равенство и неравенство.Другие операции сравнения не допустимы.
Операция @означает взятие адреса переменной: @A – адрес переменной A (или адрес первого байта массива или структуры A). Операция^ означает взятие содержимого: ^b – содержимое ячейки с адресом b (сравните положение значка ^ с тем, что используется при объявлении указателей). ^b можно использовать точно так же, как и переменную базового для указателя b типа.
Пример.
Var C: ^integer; i:integer;
Begin C:=@i; {в ячейку С записан адрес ячейки i}
C^:=1; {в ячейку с адресом С записано значение 1}…End.
Имеется встроенная константа nil, представляющая собой пустой или нулевой указатель. Эта константа, естественно, используется при присваивании и сравнении. Значениеnil означает, что указатель не хранит значения адреса какой-либо ячейки памяти. Нельзя путать пустые указатели с неопределенными, в которых может храниться остаточное, мусорное значение. Использование неопределенных указателей очень опасно, так как может привести к несанкционированному обращению к памяти.
Процедура new(p),гдеp– типированный указатель, выделяет область памяти, на которую указывает (т. е. адрес которой хранит)р. При этомp^ представляет собой переменную базового дляртипа и называется динамической переменной. Процедураdispose(p)возвращает выделенную с помощьюnew(p) память в кучу, после примененияdispose(p) значение указателяр становится неопределенным (не становится равнымnil!). Применениеdispose к пустому указателю вызывает сообщение об ошибке.
Процедура GetMem(p,n)выделяет область динамической памяти из n байтов, на которую указываетр– типированный или нетипированный указатель. ФункцияAllocMem(p)возвращает значение нетипированного указателя на область из n байтов; в отличии от GetMem, AllocMemзаполняет выделенную область нулями. ПроцедураFreeMem(p)освобождает память, полученную с помощьюGetMem или AllocMem.
Динамические массивы
Для алгоритмических языков, требующих компиляции, основной трудностью работы со статическими массивами является обязательность указания количества их элементов при объявлении. В частности, в Паскале границами индексов массива в инструкции array могут быть только константы. Единственным способом работы с массивами переменной длины являются динамические переменные.
Классический подход к работе с массивами переменной длины, который в настоящее время используется, например, в алгоритмическом языке Си, состоит в следующем. После определения числа nэлементов массива (например, посредством ввода) с помощью процедуры, аналогичнойGetMem(p,n),выделяется область памяти под массив. Указательpпри этом ссылается на первый элемент массива. Адреса остальных элементов легко вычисляются по их индексам. Например, адрес i-го элемента в одномерном массиве равен p+(i-1)*s, где s – количество байтов, занимаемых одним элементом. В Объектном Паскале такой подход невозможен, так как ограничено использование арифметических операций над указателями. Это ограничение позволяет увеличить надежность программы за счет уменьшения вероятности несанкционированного доступа к памяти из-за неправильного определения адресов.
Как альтернатива описанного выше подхода, в Объектном Паскале для работы с массивами переменной длины определен специальный тип – динамические массивы. Описание динамического массива:
Var имя_массива: Array of Array of…Array ofтип_элемента;
Ключевые слова Array of записываются в описании столько раз, сколько индексов у массива. По существу объявленноеимя_массиваявляется указателем на массив. Начальное значение индексов динамического массива равно нулю.
Выделение памяти под массив осуществляется с помощью процедуры SetLength(см. также §3.1.2). Вызов этой процедуры имеет вид:
SetLength(имя_массива, размер1, размер2,…,размерM).
В скобках указываются размеры массива по первым M (не обязательно всем) индексам.
Пример 1. В приведенном ниже фрагменте программы выделяется память под вещественный одномерный массив a размером n и под целочисленную матрицу b из n строк и m столбцов. Значения n и m предварительно задаются вводом.
Var a:Array of Real; b:Array of Array of integer; n,m:integer;
Begin
Readln(n,m);
SetLength(a,n); SetLength(b,n,m);…
Для работы с массивами (необязательно динамическими) также используются функции:
Length(a)– возвращает размер массиваaпо первому индексу;
Low(a)– возвращает наименьший номер компонента массиваa (для динамических массивов ноль);
High(a)– возвращает наибольший номер компонента массиваa;
SizeOf(a)–возвращает число байтов памяти, занимаемых массивомa.
Для освобождения памяти, отведенной под динамический массив, достаточно присвоить его имени значение nil.
Пример 2. В приведенной ниже программе осуществляется ввод и вывод динамической матрицы, размеры которой задаются вводом.
program Primer2;
Var a:Array of Array of real; n,m,i,j:integer; {n,m – размеры матрицы}
{i,j – счетчики строк и столбцов}
Begin
writeln(’Input count of rows’); readln(n);
writeln(’Input count of columns’); readln(m);
SetLength(a,n); {отводится память под указатели на строки}
writeln(’Input array ’, n, ’*’,m);
for i:=0 to High(a) do {High(a)=n-1)}
begin
Setlength(a[i],m); { отводится память под элементы строки}
for j:=0 to High(a[i]) do {High(a[i]=m-1}
read(a[i,j]);
end; readln; {закончен ввод динамического массива}
// обработка матрицы – заглушка
writeln(’output of dynamic array’);
for i:=0 to High(a) do
begin
for j:=0 to High(a[i]) do
write (a[i,j]:7:2); writeln;
a[i]:=nil; {освобождение памяти из-под строки}
end;
a:=nil;{ освобождение памяти из-под указателей на строки }
readln
End.