Программирование на языке Паскаль
Последовательное изложение основ программирования на примере алгоритмического языка Паскаль. Обзор структурной и объектно-ориентированной технологии программирования, методов проектирования, отладки и тестирования программ, использования структур данных.
Рубрика | Программирование, компьютеры и кибернетика |
Вид | учебное пособие |
Язык | русский |
Дата добавления | 13.09.2017 |
Размер файла | 1,6 M |
Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже
Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.
Program Primer;
Uses CRT;
Var a, b: Integer; a и b - переменные основной программы (глобальные)
Procedure Swap(Var x, y: Integer); x и y - входные параметры-
Var temp: Integer; переменные
Begin
temp := x;
x := y;
y := temp;
End;
Begin
ClrScr;
a := 3;
b := 5;
Swap(a, b); обращение к процедуре
WriteLn(`a=',a);
WriteLn(`b=',b);
ReadLn;
End.
На экран будет выведено:
a=5
b=3
Правила построения и использования процедур не отличаются от правил построения и использования функций, в том числе и относительно рекурсии.
Как уже отмечалось в правилах формирования подпрограмм-функций, для передачи в подпрограмму массива необходимо предварительно определить его в разделе описания типов, то есть явно задать количество его элементов и их тип. Значит, подпрограмма, формальным параметром которой является массив из десяти чисел, не сможет работать с массивом из пятнадцати чисел. Это неудобно, поэтому в списке формальных параметров подпрограмм разрешается определять открытые массивы.
Открытые массивы - это вектора, состоящие из элементов любого типа, кроме файлового. На место открытого массива в качестве фактического параметра можно передавать вектор любого размера, состоящий из элементов того же типа, что и элементы открытого массива:
Procedure Summ(a: Array Of Integer; Var summa: Integer);
Var i: Word;
s: Integer;
Begin
s:= 0;
For i:=0 To High(a) Do нумерация элементов начинается с нуля!
s:= s + a[i]; номер последнего элемента определяется с
summa:= s; помощью функции High
End;
Передавать открытый массив можно как значение, переменную или константу. Поскольку тип индексов массива не указывается, используется соглашение, по которому эти элементы нумеруются с нуля. Номер последнего элемента в массиве можно определить с помощью функции High.
Примеры: задать целочисленный вектор a длиной n элементов случайным образом с элементами от m_min до m_max..
1. Определить минимальный min и максимальный max элементы вектора и их индексы i_min, i_max. Результаты сохранить в текстовом файле out_min_max.txt:
Program Primer_1;
Uses CRT;
Const n = 10; размер вектора
m_min = -50; диапазон значений
m_max = 50; элементов вектора
Type TVector = Array [1..n] Of Integer;
Var i, i_min, i_max: Word;
min, max: Integer;
a : TVector;
out_min_max: Text; файловая переменная
Procedure Init(elem_min, elem_max: Integer; Var Vector: Array Of Integer); используется открытый массив Vector
Var i: Word;
Begin
Randomize; запуск генератора случайных чисел
For i:=0 To High(Vector) Do задание элементов массива случайными числами в диапазоне от elem_min до elem_max
Vector[i]:=elem_max - Random(elem_max - elem_min +1);
End;
Procedure Min_max(m: Word; vector: TVector; Var min, max: Integer; Var i_min, i_max: Word); используется массив vector типа TVector
Var i: Word;
Begin
min:=vector[1]; перед поиском минимального и максимального элементов
max:=vector[1]; массива за таковые принимается первый элемент i_min:=1; массива
i_max:=1;
For i:=2 To m Do поиск начинаем со второго элемента
Begin
If (vector[i] < min) Then
Begin
min:=vector[i];
i_min:=i;
End;
If (vector[i] > max) Then
Begin
max:=vector[i];
i_max:=i;
End;
End;
End;
Begin
ClrScr;
Assign(out_min_max,'d:\User\out_min_max.txt');
ReWrite(out_min_max); открытие текстового файла для записи
Init(m_min, m_max, a); инициализация массива
Writeln(out_min_max, `Исходный вектор:');
For i:=1 To n Do
Write(out_min_max, a[i]:5);
WriteLn(out_min_max);
Min_max(n, a, min, max, i_min, i_max); поиск элементов массива
WriteLn(out_min_max, `min=', min);
WriteLn(out_min_max, `i_min=', i_min);
WriteLn(out_min_max, `max=', max);
WriteLn(out_min_max, `i_max=', i_max);
Close(out_min_max); закрытие текстового файла
ReadLn;
End.
Результат работы программы:
Исходный вектор:
-1 -19 -19 -35 50 26 -47 17 1 -7
min=-47
i_min=7
max=50
i_max=5
2. Отсортировать элементы массива методом простого выбора: в массиве отыскивается минимальный элемент и меняется с первым элементом массива, из оставшихся элементов снова находится минимальный и меняется со вторым элементом, и так далее. Последний, самый большой элемент, сам станет на свое место. Результаты сохранить в текстовом файле out_sort.txt:
Program Primer_2;
Uses CRT;
Const n = 10; размер массива
m_min = -50; диапазон значений
m_max = 50; элементов массива
Type TVector = Array [1..n] Of Integer;
Var i: Word;
a : TVector;
out_sort: Text; файловая переменная
Procedure Init(m: Word; elem_min, elem_max: Integer; Var vector: TVector);
Var i: Word;
Begin
Randomize; запуск генератора случайных чисел
For i:=1 To m Do задание элементов массива случайными числами
в диапазоне от elem_min до elem_max
vector[i]:=elem_max - Random(elem_max - elem_min +1);
End;
Procedure Sort_vybor(m: Word; Var vector: TVector);
Var i, j, k: Word;
temp: Integer;
Begin
For i := 1 To m-1 Do
Begin
k := i;
temp := vector[i];
For j := i + 1 To m Do
If (vector[j] < temp) Then
Begin
temp := vector[j];
k:= j;
End;
vector[k] := vector[i];
vector[i] := temp;
End;
End;
Begin
ClrScr;
Assign(out_sort,'d:\User\out_sort.txt');
ReWrite(out_sort); открытие текстового файла для записи
Init(n, m_min, m_max, a); инициализация массива
Writeln(out_sort, `Исходный вектор:');
For i:=1 To n Do
Write(out_sort, a[i]:5);
WriteLn(out_sort);
Sort_vybor(n, a); сортировка элементов массива
Writeln(out_sort, `Отсортированный вектор:');
For i:=1 To n Do
Write(out_sort, a[i]:5);
WriteLn(out_sort);
Close(out_sort); закрытие текстового файла
ReadLn;
End.
Результат работы программы:
Исходный вектор:
-15 -31 12 -10 50 -27 36 -29 2 5
Отсортированный вектор:
-31 -29 -27 -15 -10 2 5 12 36 50
3. Отсортировать элементы массива методом простого обмена (методом пузырька): сравниваются попарно два очередных рядом стоящих элемента и при необходимости переставляются по возрастанию. После первого прохода массива его максимальный элемент становится на последнее место, после второго прохода максимальный из оставшихся становится на предпоследнее место и так далее. Таким образом, после каждого очередного прохода по массиву максимальный элемент из оставшихся как бы всплывает наверх - к концу массива. Всего необходимо n - 1 прохода. Результаты сохранить в текстовом файле out_sort.txt:
Program Primer_3;
Uses CRT;
Const n = 10; размер массива
m_min = -100; диапазон значений
m_max = 100; элементов массива
Type TVector = Array [1..n] Of Integer;
Var i: Word;
a : TVector;
out_sort: Text; файловая переменная
Procedure Init(m: Word; elem_min, elem_max: Integer; Var vector: TVector);
Var i: Word;
Begin
Randomize; запуск генератора случайных чисел
For i:=1 To m Do задание элементов массива случайными числами
в диапазоне от elem_min до elem_max
vector[i]:=elem_max - Random(elem_max - elem_min +1);
End;
Procedure Sort_obmen(m: Word; Var vector: TVector);
Var i, j, k: Word;
temp: Integer;
Begin
For i := m DownTo 2 Do
For j := 1 To i - 1 Do
If (vector[j] > vector[j+1]) Then
Begin
temp := vector[j];
vector[j] := vector[j+1];
vector[j+1]:= temp;
End;
End;
Begin
ClrScr;
Assign(out_sort,'d:\User\out_sort.txt');
ReWrite(out_sort); открытие текстового файла для записи
Init(n, m_min, m_max, a); инициализация массива
Writeln(out_sort, `Исходный вектор:');
For i:=1 To n Do
Write(out_sort, a[i]:5);
WriteLn(out_sort);
Sort_obmen(n, a); сортировка элементов массива
Writeln(out_sort, `Отсортированный вектор:');
For i:=1 To n Do
Write(out_sort, a[i]:5);
WriteLn(out_sort);
Close(out_sort); закрытие текстового файла
ReadLn;
End.
Результат работы программы:
Исходный вектор:
47 -14 58 -69 9 -19 -72 24 97 -32
Отсортированный вектор:
-72 -69 -32 -19 -14 9 24 47 58 97
4. Отсортировать элементы массива методом простых вставок: в уже отсортированной части элементов массива a1, a2, a3,…,ak отыскивается место для следующего элемента ak+1 . Результаты сохранить в текстовом файле out_sort.txt:
Program Primer_4;
Uses CRT;
Const n = 10; размер массива
m_min = -150; диапазон значений
m_max = 150; элементов массива
Type TVector = Array [1..n] Of Integer;
Var i: Word;
a : TVector;
out_sort: Text; файловая переменная
Procedure Init(m: Word; elem_min, elem_max: Integer; Var vector: TVector);
Var i: Word;
Begin
Randomize; запуск генератора случайных чисел
For i:=1 To m Do задание элементов массива случайными числами
в диапазоне от elem_min до elem_max
vector[i]:=elem_max - Random(elem_max - elem_min +1);
End;
Procedure Sort_vstavka(m: Word; Var vector: TVector);
Var i, j, k: Word;
temp: Integer;
Begin
For i := 2 To m Do
Begin
temp := vector[i];
j := i - 1;
k := 1;
While (j > 0) Do
If (vector[i] > vector[j]) Then
Begin
k := j + 1;
j := 0;
End
Else j := j - 1;
For j := i DownTo k + 1 Do
vector[j] := vector[j - 1];
vector[k] := temp;
End;
End;
Begin
ClrScr;
Assign(out_sort,'d:\User\out_sort.txt');
ReWrite(out_sort); открытие текстового файла для записи
Init(n, m_min, m_max, a); инициализация массива
Writeln(out_sort, `Исходный вектор:');
For i:=1 To n Do
Write(out_sort, a[i]:5);
WriteLn(out_sort);
Sort_vstavka(n, a); сортировка элементов массива
Writeln(out_sort, `Отсортированный вектор:');
For i:=1 To n Do
Write(out_sort, a[i]:5);
WriteLn(out_sort);
Close(out_sort); закрытие текстового файла
ReadLn;
End. Результат работы программы:
Исходный вектор:
115 -45 20 -39 91 75 44 138 -72 -63
Отсортированный вектор:
-72 -63 -45 -39 20 44 75 91 115 138
5. Отсортировать элементы массива методом быстрой сортировки К.Хоара: сравниваются элементы ai и aj , причем i = 1, j = n. Если ai < aj , то эти элементы уже отсортированы по возрастанию, поэтому значение правого индекса уменьшается на единицу, и алгоритм повторяется. Если ai > aj , то они меняются местами, останавливается правый индекс, и начинает увеличиваться левый. Обмен значениями с изменением направления движения после каждого обмена продолжается до тех пор, пока левый и правый индексы не встретятся друг с другом: i = j. В этом случае элемент ai будет стоять на своем месте в массиве: слева от него стоят элементы меньше его, а справа - больше. После этого алгоритм рекурсивно повторяется для левой и правой частей массива. Результаты сохранить в текстовом файле out_sort.txt:
Program Primer_6;
Uses CRT;
Const n = 10; размер массива
m_min = -100; диапазон значений
m_max = 100; элементов массива
Type TVector = Array [1..n] Of Integer;
Var i: Word;
a : TVector;
out_sort: Text; файловая переменная
Procedure Init(m: Word; elem_min, elem_max: Integer; Var vector: TVector);
Var i: Word;
Begin
Randomize; запуск генератора случайных чисел
For i:=1 To m Do задание элементов массива случайными числами
в диапазоне от elem_min до elem_max
vector[i]:=elem_max - Random(elem_max - elem_min +1);
End;
Procedure Sort_Hoar(m, bottom, top: Word; Var vector: TVector);
Var i, j: Word;
Str: Boolean;
temp: Integer;
Begin
i := bottom;
j := top;
str := False;
While (i < j) Do
Begin
If (vector[i] > vector[j]) Then
Begin
temp := vector[i];
vector[i] := vector[j];
vector[j] := temp;
str := Not(str);
End; {If}
If (str)
Then i := i + 1
Else j := j - 1;
End; {While}
If (i > 1) And ((i - 1) > bottom)
Then Sort_Hoar(m, bottom, i - 1, vector);
If (j < (m - 1)) And ((j + 1) < top)
Then Sort_Hoar(m, j + 1, top, vector);
End;
Begin
ClrScr;
Assign(out_sort,'d:\User\out_sort.txt');
ReWrite(out_sort); открытие текстового файла для записи
Init(n, m_min, m_max, a); инициализация массива
Writeln(out_sort, `Исходный вектор:');
For i:=1 To n Do
Write(out_sort, a[i]:5);
WriteLn(out_sort);
Sort_Hoar(n, 1, n, a); сортировка элементов массива
Writeln(out_sort, `Отсортированный вектор:');
For i:=1 To n Do
Write(out_sort, a[i]:5);
WriteLn(out_sort);
Close(out_sort); закрытие текстового файла
ReadLn;
End.
Результат работы программы:
Исходный вектор:
-62 18 -48 46 -44 -58 -95 76 4 -65
Отсортированный вектор:
-95 -65 -62 -58 -48 -44 4 18 46 76
Метод К.Хоара считается одним из самых быстрых методов сортировок.
Программные модули
Все вышеприведенные подпрограммы имеют универсальный характер, то есть ими может пользоваться любой программист. Как же проще их использовать? Разумеется, можно копировать тексты этих подпрограмм, пользуясь, например, буфером обмена, но это утомительное занятие и неизящное решение. Кроме того, программы, содержащие множество процедур и функций, становятся громоздкими и неудобными в отладке.
В Паскале есть замечательный инструмент для преодоления этих неприятностей - программные модули.
Прежде чем приступить к рассмотрению модульного программирования, разберемся, как происходит обработка исходного текста программы (кода программы) в системе программирования Turbo Pascal (Borland Pascal).
Программа, написанная на любом языке программирования, перед выполнением должна быть приведена к виду, пригодному для исполнения на компьютере, то есть переведена с конкретного языка программирования на машинный язык компьютера.
Машинный язык - это система команд, которую понимает и может выполнить процессор.
Другими словами, исходный код (текст) программы перед выполнением должен быть преобразован в исполняемый код. Это перевод английского слова executable , от него же и произошло известное расширение имен исполняемых файлов - .exe. Исходный же текст программы на Паскале имеет расширение имени - .pas. Обратное преобразование невозможно - из исполняемых файлов уже нельзя восстановить исходный текст программы на Паскале, поэтому все исходные тексты должны сохраняться для их последующей доработки.
При работе в Turbo Pascal исполняемый код формируется в оперативной памяти и без записи его на диск сразу выполняется. При работе в среде Borland Pascal исполняемый файл формируется автоматически, поэтому файл с расширением .exe появляется в текущем каталоге после первого удачного запуска программы.
Процесс преобразования исходного кода в исполняемый происходит в два этапа:
компиляция,
компоновка (линковка).
На этапе компиляции исходная программа преобразуется в машинный код, но он пока не пригоден для исполнения, так как в него не включены коды стандартных процедур и функций, которые находятся в отдельном файле Turbo.tpl (это библиотека Turbo Pascal). Код программы, полученной после компиляции, называют объектным кодом. Библиотека Turbo Pascal тоже является объектным кодом. На этапе компоновки к объектному коду программы добавляется объектный код стандартных процедур и функций из библиотеки Turbo Pascal. В результате он превращается в полноценный исполняемый код.
Компиляция и компоновка - это два различных процесса. Первый из них выполняет программа-компилятор (compiler). Ее основное назначение - проверка программы на наличие синтаксических ошибок и, в случае их отсутствия, формирование объектного кода. Процесс же компоновки выполняет программа-компоновщик (редактор связей, linker). Ее назначение - добавить к программе весь недостающий код из других файлов, скомпоновав полноценный исполняемый код.
Отсюда вытекает очень важный вывод: если компилятор имеет возможность обрабатывать не только законченные программы, но и особым образом оформленные совокупности подпрограмм, то отдельные части программы можно компилировать отдельно и хранить на внешнем носителе в откомпилированном виде. Затем компоновщик соберет объектные коды из разных файлов, и в результате будет получен исполняемый код для всей программы.
Компилятор Turbo Pascal обладает возможностью раздельной компиляции. В Паскале для этих целей введено понятие программных модулей. Программный модуль оформляется как отдельно компилируемая программная единица, содержащая различные элементы раздела описаний и, возможно, некоторые операторы. В состав модуля входят описания констант, переменных, типов, процедур и функций. Процедуры и функции, содержащиеся в модуле, подключаются к основной (головной) программе на этапе компоновки. Хранится модуль, как в исходном, так и откомпилированном виде на внешних носителях.
В этом и заключается один из наиболее фундаментальных принципов современных технологий программирования - принцип модульности. На практике реализация данного принципа предполагает выполнение двух условий:
при разработке программы необходимо выделять подпрограммы таким образом, чтобы можно было бы воспользоваться уже имеющимися модулями,
разработку новых процедур и функций следует выполнять таким образом, чтобы полученные модули можно было бы использовать в качестве составных частей для решения других задач.
Таким образом, принцип модульности отлично дополняет структурный подход к разработке программ, позволяя многократно использовать разработанные и отлаженные модули.
Преимущества такого подхода к созданию программ очевидны:
программа получается понятнее, ее легче совершенствовать в дальнейшем,
отдельные модули могут разрабатываться различными программистами, так как это относительно автономные программные единицы,
написанные модули могут быть использованы и в других программах,
модули, включаемые в исходный код программы, хранятся на диске в откомпилированном виде. Поэтому процесс подготовки всей программы к выполнению займет меньше времени - компилироваться будет только основная программа,
при выполнении программы в среде Turbo Pascal исполняемый код модулей размещается в отдельных сегментах памяти, что дает возможность создавать программы большого размера (более 64К).
В Паскале используются стандартные и пользовательские модули.
Стандартные модули: SYSTEM, CRT, GRAPH, DOS, PRINTER, OVERLAY образуют системную библиотеку Паскаля Turbo.tpl (Turbo Pascal Library).Модуль SYSTEM подключается к программе пользователя автоматически, остальные модули указываются в операторе Uses:
Uses CRT, GRAPH;
Пользовательские модули создаются самими программистами.
Структура модуля
Модуль - это самостоятельная отдельно компилируемая программная единица, поэтому его структура напоминает структуру обычной программы:
заголовок модуля
интерфейсный раздел
раздел реализации
инициирующий раздел.
Собственно программный код располагается в исполняемой части, иногда в инициирующей. Заголовок и интерфейсная часть задают название модуля и перечисление всех программных элементов, которые представляет этот модуль тем программам или другим модулям, которые будут его использовать. Исходный текст модуля, как и любой Паскаль-программы, содержится в файле с расширением имени .pas. После компиляции модуля на диске создается файл с объектным кодом и расширением имени .tpu. (Turbo Pascal Unit).
Заголовок модуля содержит слово Unit и имя модуля:
Unit Abc;
Это имя указывается в разделе Uses программы, которой необходим доступ к этому модулю. Имя модуля должно совпадать с именем того файла, в который помещается исходный текст модуля.
Интерфейсный раздел обеспечивает взаимодействие данного модуля с головной программой и другими модулями. В нем объявляются глобальные, то есть доступные другим модулям и головной программе объекты: константы, типы, переменные, заголовки функций и процедур:
Interface
Uses список модулей, используемых интерфейсным разделом
Const объявление глобальных констант
Type объявление глобальных типов
Var объявление глобальных переменных
Function заголовки функций и процедур со списками формальных
Procedure параметров, видимых другим модулям и головной программе
Раздел реализации содержит описание функций и процедур, заголовки которых представлены в интерфейсном разделе. Кроме того, здесь могут быть объявлены локальные, то есть доступные только в пределах данного модуля метки, константы, типы и переменные, если они применяются в инициирующем разделе:
Implementation
Uses список модулей, используемых разделом реализации (скрытых)
Const объявление локальных констант
Type объявление локальных типов
Var объявление локальных переменных
Function описание указанных ранее функций и процедур без списка Procedure формальных параметров
Этот раздел скрыт от вызывающей программы и других модулей.
В инициирующем разделе могут содержаться операторы, которые до передачи управления вызывающей программе или модулям выполняют некоторые подготовительные действия, например, инициализацию глобальных переменных или открытие необходимых файлов:
Begin…….
End.
Раздел выполняется только один раз при обращении к данному модулю. Если этот раздел не нужен, то слово Begin не пишется. В конце модуля стоит слово End с точкой.
Пример: создать модуль My_modul, который содержал бы
функцию Geron для определения площади треугольника по формуле Герона,
процедуру Swap для обмена значениями двух переменных вещественного типа,
текстовый файл f.txt для записи в него результатов работы функции Geron
Unit My_modul;
Interface интерфейсный раздел
Var f: Text;
{определение площади треугольника по формуле Герона - по трем его сторонам a, b, c - вещественного типа}
Function Geron(a, b, c: Real): Real;
{обмен значениями двух переменных x и y - вещественного типа}
Procedure Swap(Var x, y : Real);
Implementation раздел реализации
Function Geron;
Var p: Real;
Begin
p := (a + b + c) / 2.0; {полупериметр}
Geron := Sqrt(p * (p -a) * (p - b) * (p - c));
End;
Procedure Swap;
Var temp: Real;
Begin
temp := x;
x := y;
y := temp;
End;
Begin инициирующий раздел
Assign(f, `D:\User\f.txt');
End.
Сохраним этот файл на диске с именем My_modul.pas.
Компиляция модулей
В среде Turbo Pascal имеются средства, управляющие способом компиляции модулей и облегчающие разработку крупных программных проектов.
Результатом компиляции модуля является файл с тем же именем и расширением tpu (Turbo Pascal Unit), который можно хранить на диске так же, как и exe-файл.
Меню Compile, управляющее процессом компиляции, содержит следующие опции:
Compile
Make
Build
Destination (Memory, Disk)
Primary File…
Первые три опции - это режимы компиляции:
Compile - все модули, входящие в компилируемый модуль, должны быть предварительно откомпилированы (имеется их объектный код). Если какой-либо файл tpu не обнаружен, то система ищет одноименный файл с исходным текстом (расширением pas) и при обнаружении компилирует его,
Make - система следит за возможными изменениями, внесенными программистом в исходный текст модуля. Если в текст модуля были внесены изменения, то система заново его компилирует и только потом приступает к компиляции основной программы. Кроме того, если изменения были внесены в интерфейсный раздел модуля, то будут перекомпилированы и все другие модули, обращающиеся к нему,
Build - автоматически компилируются все модули, независимо от времени их обновления. Это самый надежный, но и самый медленный режим подготовки модульной программы.
Далее идут опции:
Destination - для задания места сохранения tpu- и exe-файлов: при значении Disk они будут сохранены на текущем диске, Memory - в оперативной памяти. В среде Borland Pascal эти файлы автоматически сохраняются на диске, там нет этой опции в меню Compile,
Primary File - позволяет задавать файл, который будет автоматически добавляться в начало исходного текста перед компиляцией. Таким способом удобно отлаживать модули, подключая к ним головную программу в качестве Primary File. При этом в процессе отладки не придется постоянно перемещаться между окнами основной программы и отлаживаемого модуля.
Полностью отлаженный и протестированный модуль в виде tpu-файла может быть распространен с приложением к нему заголовка и интерфейсного раздела (но не раздела реализации!) исходного текста модуля в качестве инструкции по использованию с подробными комментариями. Обращаться к такому модулю в вызывающей программе можно указанием его имени в операторе Uses:
Uses CRT, My_modul;
Взаимное использование модулей
Модули могут обращаться друг к другу косвенно или рекурсивно.
При косвенном использовании модулей один из них использует другой:
Unit A; Unit B;
Interface Interface
Uses B; .....
....... End.
End.
Пусть в головной программе используется только модуль A:
Uses CRT, A;
В этом случае нет необходимости указывать и модуль B:
Uses CRT, A, B;
При рекурсивном использовании модулей они взаимно обращаются друг к другу:
Unit A; Unit B;
Interface Interface
Uses B; Uses A;....... .......
End. End.
Если какой-нибудь из них подключить к программе:
Uses CRT, A;
то будет зафиксирована ошибка:
Error 68: Circular Unit Reference (A)
Взаимное использование возможно, если модули подключить из раздела реализации:
Unit A; Unit B;
Interface Interface....... .......
Implementation Implementation
Uses B; Uses A;....... .......
End. End.
Особенности выполнения инициирующих разделов
Если в модуле имеется инициирующий раздел, то его операторы выполняются до операторов программы, к которой данный модуль подключен. Если несколько модулей с инициирующими разделами:
Unit A; Unit B;
Interface Interface
Const x = 1; Const x = 2; x - глобальная
Implementation Implementation переменная
End. End.
подключены к программе:
Program Primer;
Uses WinCRT, A, B;
Begin
ClrScr;
WriteLn('x=', x);
End.
то они выполняются в порядке подключения, и одноименной переменной будет присвоено последнее значение. На экран будет выведено:
x=2
Последним подключен модуль B, в котором глобальная x = 2.
Изменим порядок подключения:
Program Primer;
Uses WinCRT, B, A;
Begin
ClrScr;
WriteLn('x=', x);
End.
В этом случае на экране появится:
x=1
так как в модуле A глобальная x = 1.
Если в программе необходим доступ ко всем переменным, в том числе и одноименным, из интерфейсов всех модулей, то указываются их составные имена, похожие на имена полей записей:
Program Primer;
Uses WinCRT, A, B;
Begin
ClrScr;
WriteLn('A.x=', A.x);
WriteLn('B.x=', B.x);
End.
На экран будет выведено:
A.x=1
B.x=2
Ссылки и динамические переменные
Между объектами реального мира, которые моделируются на компьютерах, существуют разнообразные, постоянно меняющиеся связи. Эти связи, как и сами объекты, могут появляться и исчезать. Поэтому если мы хотим описать в программе группу с переменным числом объектов, связи между которыми тоже подвержены изменениям, нужны соответствующие структуры. Эти структуры должны позволять устанавливать, изменять и разрывать связи между моделируемыми объектами, а также порождать или уничтожать сами объекты.
Для этой цели в Паскале используются ссылки и динамические переменные.
До сих пор мы рассматривали только статические структуры. Этим термином обозначаются структуры данных (массивы, множества, файлы, записи), которые возникают непосредственно перед выполнением программы в соответствии со своим описанием, существуют в течение всего времени ее выполнения, и размер которых задается заранее с помощью описания их типов и не изменяется в ходе выполнения программы.
Однако при решении многих задач мы заранее, то есть на этапе написания программы, не знаем не только размера того или иного программного объекта (структуры данных), но и даже того, будет ли вообще нужен этот объект. Такого рода программные объекты или структуры данных, возникающие уже в процессе выполнения программы по мере необходимости, размер которых определяется или изменяется при ее выполнении, называются динамическими объектами или структурами.
В Паскале для работы с динамическими объектами предусматривается специальный тип данных - ссылки или указатели. Значениями этого типа данных являются ссылки на какой-либо программный объект. По этим ссылкам осуществляется непосредственный доступ к этому объекту. На машинном языке такая ссылка представляется указанием места в оперативной памяти (адреса ячейки памяти), в котором хранится значение соответствующего объекта.
В этом случае для описания действий над динамическими объектами каждому такому объекту сопоставляется в программе простая переменная ссылочного типа. В терминах этих ссылочных переменных и описываются действия над соответствующими динамическими объектами. Значения же переменных ссылочного типа, как обычно, определяются уже в процессе выполнения программы, а для достаточно удобного формирования таких значений предусматриваются специальные операторы.
Таким образом, статическая переменная описывается в программе и обозначается с помощью имени (идентификатора), которое и является адресом ячейки памяти, где хранится значение этой переменной. Динамическая же переменная не указывается в описании переменных и ее нельзя обозначить с помощью имени. К ней можно обратиться с помощью ссылки (переменной ссылочного типа), в которой хранится адрес ячейки памяти, где записано значение одноименной динамической переменной.
Ссылки (указатели) можно описать в программе двумя способами.
При первом способе в разделе определения типов Type указывается имя типа ссылки, ставятся знаки = и ^ (карат), указывается тип переменных, к которому будет относиться эта ссылка:
Type TPntint = ^Integer;
TPntchar = ^Char;
TPntReal = ^Real;
В соответствии с этим описанием TPntint является типом ссылки на динамические объекты целого типа, TPntchar - динамические объекты символьного типа, TPntReal - динамические объекты вещественного типа. Сейчас можно описать переменные, значениями которых являются ссылки - переменные ссылочного типа:
Var a, b: TPntint;
x, y: TPntchar;
s, r: TPntReal;
При втором способе переменные ссылочного типа можно вводить обычным путем, с помощью их описания в разделе Var:
Var a, b: ^Integer;
x, y: ^Char;
s, r: ^Real;
Переменные a, b, x, y, s, r будут хранить адреса ячеек памяти, где находятся значения одноименных динамических переменных. В порядке исключения такие переменные не описываются в разделе Var, а производятся в программе с помощью оператора New:
New(a);
New(b);……
Оператор New, во-первых, создает динамическую переменную соответствующего одноименной ссылке типа, и, во-вторых, соединяет эту динамическую переменную со ссылкой на нее.
Таким образом, оператор New играет для динамической переменной ту же роль, что и описание для статической.
В Паскале для работы с динамическими переменными введено понятие переменной с указателем - это переменная ссылочного типа, за которой следует символ ^ : x^, y^, a^. Стрелка после имени переменной ссылочного типа говорит о том, что речь идет не о значении данной переменной (адресе ячейки памяти), а о значении одноименной динамической переменной, то есть переменной, на которую указывает эта переменная ссылочного типа.
Таким образом, значение переменной с указателем тождественно значению одноименной динамической переменной. Она может быть использована во всех выражениях и операторах, где допускается использование переменных того типа, что и тип одноименной динамической переменной:
New(a);
New(b);
WriteLn(a^, ` `, b^); на экран будет выведено содержание ячеек
памяти, адреса которых содержатся в
переменных a и b
WriteLn(a, ` `, b); ошибка! Нельзя выводить на экран адреса
ячеек памяти (Error 64)
a^ := 3;
b^ := 5;
WriteLn(a^, ` `, b^); на экран будет выведено: 3 5
a := b; переменная a содержит адрес той же ячейки, что и переменная b - они указывают на одну и ту же ячейку памяти
WriteLn(a^, ` `, b^); на экран будет выведено: 5 5
b := Nil; ссылка b никуда не указывает
WriteLn(a^, ` `, b^); ошибка! Значение b^ не определено!
Представим для наглядности полученные результаты в виде рисунков, причем в прямоугольниках укажем текущие значения соответствующих переменных, а стрелками - связи между ними:
ссылки динамические переменные
New(a);
New(b);
WriteLn(a^, ` `, b^);
Определены адреса a и b динамических переменных a^ и b^, но сами их значения пока не заданы, поэтому на экран будут выведены значения, оставшиеся в ячейках памяти с указанными адресами после решения предыдущей задачи.
a^ := 3;
b^ := 5;
WriteLn(a^, ` `, b^);
Обычное присваивание значений переменным: динамической переменной a^ присвоено значение 3, а динамической переменной b^ - значение 5. Эти же значения и выводятся на экран.
a := b;
WriteLn(a^, ` `, b^);
Указателю a присвоено новое значение - значение адреса ячейки памяти, хранившееся в указателе b. Поэтому сейчас оба указателя хранят один и тот же адрес - адрес b. Они указывают на одну и ту же динамическую переменную b^. Адрес же динамической переменной a^ утерян, поэтому ее значение становится недоступным. Значит, на экран будут выведены два одинаковых числа, являющиеся текущими значениями переменных a^ и b^: 5 и 5.
b := Nil;
WriteLn(a^, ` `, b^);
Указатель b принимает значение пустой ссылки Nil - он перестает указывать на какую-нибудь динамическую переменную b^, поэтому нельзя выводить на экран ее значение.
Таким образом, использование динамических переменных отличается следующим:
вместо описания самих динамических переменных в программе дается описание ссылок на них (статических переменных ссылочного типа), поставленных в соответствие одноименным динамическим переменным,
до своего использования каждая динамическая переменная должна быть порождена с помощью оператора New,
значение динамической переменной задается с помощью переменной с указателем,
к переменной с указателем можно применять все те операции, которые допустимы и для статической переменной того же типа.
Над значениями переменных ссылочного типа - адресами динамических переменных - в Паскале кроме операции присваивания определены две операции сравнения: = и <>.
Два значения ссылочного типа равны между собой, если они оба равны Nil, либо указывают на один и тот же динамический объект (ячейку памяти). Во всех остальных случаях имеет место неравенство.
Если в процессе выполнения программы динамический объект, созданный оператором, например New(a), становится ненужным, то его можно уничтожить оператором Dispose(a). При этом динамический объект, на который указывает ссылочная переменная a , уничтожается, занимаемое им место в памяти освобождается, а значение переменной a становится неопределенным. Оператор Dispose уничтожает только сам динамический объект, но не указатель на него:
New(a);
New(b);
a^ := 3;
b^ := 5;
Dispose(a);
a := b;
b := Nil;
Динамические структуры данных
Основное преимущество, предоставляемое ссылками и динамическими переменными, состоит в том, что они дают возможность создавать объекты со сложной, изменяющейся в процессе работы программы структурой - динамические структуры данных - связные списки, стеки, очереди, деревья.
Динамические структуры не имеют постоянного размера, поэтому память под отдельные элементы таких структур выделяется в момент, когда они создаются в процессе выполнения программы, а не во время трансляции. Когда в элементе структуры нет необходимости, занимаемая им память освобождается.
Поскольку элементы динамических структур располагаются в памяти не по порядку и даже не в одной области, адрес элемента такой структуры не может быть вычислен из адреса начального или предыдущего элемента, как при работе с массивами. Связь между элементами динамической структуры устанавливается через указатели, содержащие адреса элементов в памяти. Такое представление данных в памяти называется связным.
Таким образом, кроме информационных полей, ради которых создается структура и которые являются видимыми для пользователя, динамические структуры содержат поля для связи с другими элементами, видимые только для программиста-разработчика. С помощью связного представления данных обеспечивается высокая изменчивость структуры.
Динамические структуры обладают следующими преимуществами:
размер структуры ограничивается только объемом памяти компьютера,
при изменении логической последовательности элементов структуры (добавлении или удалении элемента, изменении порядка следования элементов) требуется только коррекция указателей.
С другой стороны, такие структуры обладают рядом недостатков:
работа с указателями требует высокой квалификации программиста,
на указатели расходуется дополнительная память
дополнительный расход времени на доступ к элементам связной структуры.
Связные списки
Связный список - это динамическая структура, имеющая вид цепочки связанных между собой элементов, причем каждый предыдущий элемент в ней хранит информацию о месте (адресе ячейки памяти), где расположен следующий за ним элемент.
Такая ситуация напоминает очередь к врачу в приемной: каждый пациент знает, за кем он занимал очередь, хотя все посетители могут сидеть в каком угодно порядке на свободных стульях.
Связанный список состоит из элементов типа запись, причем каждый элемент имеет два поля - информационное и ссылочное. В информационном поле (полях) хранится значение элемента списка - числа, строки и т.д., а в ссылочном - ссылка (адрес ячейки памяти) на следующий за ним элемент:
Type TPoint = ^TElement;
TElement = Record
Inf: Integer;
Next: TPoint;
End;
Var head, q : TPoint;
Определен новый тип TPoint - ссылка на объекты типа TElement, причем TElement - это запись, имеющая два поля: Inf - целого типа и Next - типа TPoint. Здесь мы впервые сталкиваемся с ситуацией, когда в правой части определения для типа TPoint встречается имя типа TElement, который определен позже. В Паскале разрешается такое рекурсивное определение типов, если один из них является ссылочным.
Таким образом, переменные head и q типа TPoint являются записями, одно из полей которых содержит ссылку на адрес ячейки памяти, отводимой для переменной этого же типа. Значит, каждый элемент создаваемого списка будет содержать ссылку на такой же элемент списка. Признаком того, что данный элемент является последним в списке, является равенство поля ссылки этого элемента значению Nil - пустой ссылки. На каждый элемент списка, кроме первого, имеется ссылка от предыдущего элемента. Поэтому при формировании любого списка необходимо вводить переменную, значение которой является ссылка на текущий первый элемент списка - голову списка. Такой переменной у нас является head. Если список еще не сформирован, то есть в нем нет ни одного элемента (пустой список), то значение этой переменной должно равняться Nil.
Построим список из трех элементов, содержащих числа 5, -3, -12 (причем 5 - голова, а -12 - хвост). Пусть в ссылочном поле переменной head всегда хранится адрес текущего первого элемента списка. Переменную q будем использовать для выделения с помощью оператора New(q) места в памяти для размещения очередного элемента списка.
В начале построения списка ни одного элемента в нем нет - список пуст, поэтому нет и его начала:
New(head);
Head := Nil;
Список начнем строить с последнего элемента, равного -12 : определим для него место в памяти и информационную часть:
New(q);
q^.Inf := -12;
Сейчас этот элемент является первым (и пока единственным), поэтому одновременно и последним элементом списка. Поэтому ссылочная часть его должна быть равна head, имеющему значение Nil - за этим элементом других элементов нет:
q^.Next := head;
а переменная head должна уже содержать ссылку на этот первый созданный элемент списка:
head := q;
Таким образом, переменная head сейчас хранит адрес ячейки памяти, созданной операцией New(q), в которой записан первый элемент списка -12.
Вставим перед ним элемент, равный -3: определим для него место в памяти и информационную часть:
New(q);
q^.Inf := -3;
При этом в памяти сохраняется уже созданный элемент списка, ссылка на который хранится в head :
Вновь созданный элемент будет первым элементом списка, поэтому ссылку head на последний (старый первый) элемент поместим в его ссылочную часть:
q^.Next := head;
а в освободившуюся переменную head поместим ссылку на него - новый первый элемент списка (эта переменная всегда должна указывать на голову списка):
head := q;
Наконец, создадим первый (в порядке следования) элемент списка, равный 5:
New(q);
q^.Inf := 5;
Поместим в его ссылочную часть ссылку на ранее созданный (следующий за ним в списке) элемент, равный -3, а в переменную head - ссылку на него самого:
q^.Next := head;
head := q;
В результате создан связный список, в каждом элементе которого хранится адрес (ссылка) следующего за ним элемента, а ссылка на первый элемент списка находится в переменных head и q.
Ссылочное поле (в нашем случае .Next) само является указателем, поэтому, например, значением переменной head^.Next^.Inf будет являться информационное поле второго по списку элемента, т.е. -3, а значением переменной head^.Next^.Next - ссылочное поле этого элемента, т.е. ссылка на третий элемент списка. Так, наращивая переменную head, можно добраться до конца списка.
Таким образом, рассмотренный способ построения списка “с хвоста” заключается в создании пустого списка и повторяющемся выполнении ряда однотипных шагов, добавляющих в начало списка новые элементы.
Например, программа построения списка, элементами которого являются квадраты целых чисел от 1 до n, имеет вид (воспользуемся имеющимся описанием переменных):
New(head);
head := Nil;
For i:=n DownTo 1 Do
Begin
New(q);
q^.Inf := i*i;
q^.Next := head;
head := q;
End;
После создания этого списка значением переменной head будет являться ссылка на его первый элемент. Прочитаем созданный список - выведем на экран информационные поля его элементов, начиная с первого:
q := head; указатель - на первый элемент списка
While (q<>Nil) Do пока ссылка не пустая (последний элемент)
Begin
Write(q^.Inf:6); выводим значение очередного элемента
q := q^.Next; делаем шаг по списку - берем следующий элемент
End;
В данном случае при выполнении цикла While значением указателя q будут являться поочередно ссылки на первый, второй, третий и т.д. элементы списка, и, наконец, Nil. Это происходит потому, что после присваивания
q := q^.Next;
значением переменной q будет или ссылка на следующий элемент списка, хранящаяся в ссылочной части этого текущего элемента, или Nil, если достигнут конец списка.
Пользуясь этим способом перехода от предыдущего элемента к последующему, можно просмотреть или весь список от начала до конца, или его часть.
Пример: ввести с клавиатуры последовательность целых чисел (конец ввода - число 0), сформировать из них список, определить количество введенных чисел, вывести список на экран.
Интерфейс:
Первое число: -12
Следующее число: -3
Следующее число: 5
Следующее число: 0
Введено чисел: 3
Введенные числа:
5 -3 -12
Программа:
Program Spisok;
Uses CRT;
Type TPoint = ^TElement;
TElement = Record
Inf: Integer;
Next: TPoint;
End;
Var head, q : TPoint;
Begin
ClrScr;
New(head); head - указатель на голову списка
head^.Inf := 0; количество элементов в списке
head^.Next := Nil; списка еще нет
New(q); формируем первый элемент
Write(`Первое число: ');
ReadLn(q^.Inf); вводим его информационную часть
If (q^.Inf=0) если ввели 0,
Then Exit; то выходим из программы
head^.Inf := 1; в списке один элемент
q^.Next := head^.Next; вставляем его в голову списка
head^.Next := q; в head^.Next адрес головы списка
Repeat
New(q); формируем очередной элемент
Write(`Очередное число: ');
ReadLn(q^.Inf); вводим его информационную часть
If (q^.Inf=0) если ввели 0,
Then Break; то выходим из цикла ввода
head^.Inf := head^.Inf + 1; увеличиваем счетчик элементов на 1
q^.Next := head^.Next; вставляем элемент в голову списка
head^.Next := q; в head^.Next адрес головы списка
Until (q^.Inf = 0);
WriteLn(`Введено чисел: ', head^.Inf);
WriteLn(`Введенные числа:');
q := head^.Next; текущую ссылку - на первый элемент
While (q <> Nil) Do пока не конец списка
Begin
Write(q^.Inf:5); выводим очередной элемент
q := q^.Next; ссылку - на следующий элемент
End;
WriteLn;
ReadLn;
End.
Основное преимущество связных списков перед статическими структурами данных, например, массивами, заключается в том, что их можно изменять, включая в них новые элементы или исключая ненужные, причем эти операции могут производиться в любом месте списка.
Добавление нового элемента в список
Пусть имеется связный список из трех чисел: 5, -3, -12.
Добавим в описание переменных переменную ссылочного типа r:
Var head, q, r: TPoint;
Список сформирован, и значениями переменных head и q является ссылка на первый элемент списка:
Необходимо после элемента -3 вставить элемент с информационной частью, равной 17.
Для включения нового элемента в готовый список выполняются следующие действия:
1. создается новый элемент и заполняется его информационное поле:
New(r);
r^.Inf := 17;
2. в списке находится элемент, после которого должен стоять новый, в данном случае элемент -3; для этого используем переменную q :
While (q <> Nil) Do пока не дошли до конца списка
If (q^.Inf = -3) если нашли нужный элемент,
Then Break то выходим из цикла поиска,
Else q := q^.Next; иначе делаем шаг по списку
сейчас ссылка q указывает на элемент -3 , то есть q^.Inf = -3, а поле q^.Next содержит адрес элемента -12:
3. в ссылочное поле нового элемента r^.Next помещается адрес, стоящий в ссылочном поле найденного элемента (адрес следующего за ним элемента, в данном случае элемента -12, этот адрес хранится в q^.Next):
r^.Next := q^.Next;
сейчас оба элемента (17 и -3) будут соединены с элементом -12,
4. в ссылочное поле найденного элемента -3 q^.Next помещается адрес нового элемента 17, который хранится на ссылке r:
q^.Next := r;
Пример: сформировать список из элементов 5, -3, 17, -12 и вывести его на экран. Добавлять с клавиатуры новые элементы после заданных (конец ввода - число 0), каждый раз выводя новый список на экран.
Интерфейс:
Создание списка
Первое число: -12
Следующее число: 17
Следующее число: -3
Следующее число: 5
Следующее число: 0
Введено чисел: 4
Введенные числа:
5 -3 17 -12
Вставка элементов в список
Новый элемент: -2
После какого: -3
Новый список:
5 -3 -2 17 -12
Новый элемент: 15
После какого: -12
Новый список:
5 -3 -2 17 -12 15
Новый элемент: 9
После какого: 5
Новый список:
5 9 -3 -2 17 -12 15
Новый элемент: 20
После какого: 10
Такого элемента в списке нет
Список:
5 9 -3 -2 17 -12 15
Новый элемент: 0
Список:
5 9 -3 -2 17 -12 15
Программа:
Program Spisok;
Uses CRT;
Type TPoint = ^TElement;
TElement = Record
Inf: Integer;
Next: TPoint;
End;
Var head, q, r : TPoint;
posle: Integer;
flag: 0..1; флаг поиска (0 - элемент не найден)
Procedure Formir_spisok;
Begin
New(head); head - указатель на голову списка
head^.Inf := 0; количество элементов в списке
head^.Next := Nil; списка еще нет
New(q); формируем первый элемент
Write(`Первое число: ');
ReadLn(q^.Inf); вводим его информационную часть
If (q^.Inf=0) если ввели 0,
Then Exit; то выходим из процедуры
head^.Inf := 1; в списке один элемент
q^.Next := head^.Next; помещаем его в голову списка
head^.Next := q; в head^.Next адрес головы списка
Repeat
New(q); формируем очередной элемент
Write(`Очередное число: ');
ReadLn(q^.Inf); вводим его информационную часть
If (q^.Inf=0) если ввели 0,
Then Break; то выходим из цикла ввода
head^.Inf := head^.Inf + 1; увеличиваем счетчик элементов на 1
q^.Next := head^.Next; вставляем элемент в голову списка
head^.Next := q; в head^.Next адрес головы списка
Until (q^.Inf = 0);
End;
Procedure Vyvod_spisok; процедура вывода списка
Begin
q := head^.Next; текущую ссылку - на первый элемент
While (q <> Nil) Do пока не конец списка
Begin
Write(q^.Inf:5); выводим очередной элемент
q := q^.Next; ссылку - на следующий элемент
End;
WriteLn;
End;
Begin головная программа
ClrScr;
WriteLn(`Создание списка');
WriteLn;
Formir_spisok; обращение к процедуре создания списка
WriteLn(`Введено чисел: ', head^.Inf);
WriteLn(`Введенные числа:');
Vyvod_spisok; обращение к процедуре вывода списка
WriteLn;
WriteLn(`Вставка элементов в список');
WriteLn;
Repeat
New(r);
WriteLn;
Write(`Новый элемент: ');
ReadLn(r^.Inf); информационная часть нового элемента
If (r^.Inf = 0) если она равна нулю,
Then Break; то выходим из цикла ввода
Write(`После какого: ');
ReadLn(posle);
flag := 0; флаг поиска равен нулю - элемент пока не найден
q := head^.Next; поисковый указатель q - в голову списка
While (q <> Nil) Do пока не конец списка
If (q^.Inf = posle) ищем нужный элемент
Then
Begin
flag := 1; если элемент найден:
Break; выходим из цикла поиска
End
Else q := q^.Next; иначе делаем шаг по списку
If (flag = 0) Then если элемент не найден:
Begin
WriteLn(`Такого элемента в списке нет');
WriteLn(`Список:');
Vyvod_spisok; выводим список
Continue; и продолжаем цикл ввода
End;
r^.Next := q^.Next; если элемент найден,
q^.Next := r; то вставляем его в список
head^.Inf := head^.Inf + 1; увеличиваем счетчик элементов на единицу
WriteLn;
WriteLn(`Новый список:');
Vyvod_spisok; выводим новый список
Until (r^.Inf = 0); окончание цикла ввода
WriteLn(`Список:');
Vyvod_spisok; выводим окончательный список
ReadLn;
End.
Удаление элемента из списка
Пусть имеется связный список из трех чисел: 5, -3, -12.
Список сформирован, и значениями переменных head и q является ссылка на первый элемент списка:
Необходимо удалить из списка элемент -3.
Для удаления (исключения) существующего элемента из списка выполняются следующие действия:
1. указатели q (поисковый) и r (отстает от поискового на шаг) ставим в голову списка:
q := head^.Next; на первый элемент списка
r := head; на указатель на голову списка
2. в списке отыскивается удаляемый элемент, для этого используем поисковый указатель q :
While (q <> Nil) Do пока не дошли до конца списка
If (q^.Inf = -3) если нашли нужный элемент,
Then Break то выходим из цикла поиска,
Else
Begin
r := q; иначе подтягиваем r к q
q := q^.Next; и делаем шаг по списку указателем q
End;
сейчас ссылка q указывает на элемент -3 , то есть q^.Inf = -3, а поле q^.Next содержит адрес элемента -12. Ссылка r указывает на предыдущий элемент списка, то есть на 5, а в r^.Next содержится адрес удаляемого элемента - r^.Next = q :
3. в ссылочное поле r^.Next помещается адрес, хранящийся в q^.Next, то есть адрес элемента -12:
r^.Next := q^.Next;
Сейчас оба элемента (5 и -3) будут соединены с элементом -12,
а связь между элементами 5 и -3 разрывается.
4. освобождаем память от удаленного элемента -3 и возвращаем указатели q и r в голову списка:
Dispose(q); удаляем из памяти элемент -3
q := head^.Next; на первый элемент списка
r := head; на указатель на голову списка
Пример: сформировать список из элементов 5, -3, 17, -12 и вывести его на экран. Удалить из списка несколько элементов (конец удаления - число 0), каждый раз выводя новый список на экран.
Интерфейс:
Создание списка
Первое число: -12
Следующее число: 17
Следующее число: -3
Следующее число: 5
Следующее число: 0
Введено чисел: 4
Введенные числа:
5 -3 17 -12
Удаление элементов из списка
Удаляемый элемент: 17
Новый список:
5 -3 -2 -12
Удаляемый элемент: 5
Новый список:
-3 -2 -12
Удаляемый элемент: 10
Такого элемента в списке нет
Список:
-3 -2 -12
Удаляемый элемент: 0
Список:
-3 -2 -12
Программа:
Program Spisok;
Uses CRT;
Type TPoint = ^TElement;
TElement = Record
Inf: Integer;
Next: TPoint;
End;
Var head, q, r : TPoint;
poisk: Integer;
flag: 0..1; флаг поиска (0 - элемент не найден)
Procedure Formir_spisok;
Begin
New(head); head - указатель на голову списка
head^.Inf := 0; количество элементов в списке
head^.Next := Nil; списка еще нет
New(q); формируем первый элемент
Write(`Первое число: ');
ReadLn(q^.Inf); вводим его информационную часть
If (q^.Inf=0) если ввели 0,
Then Exit; то выходим из процедуры
head^.Inf := 1; в списке один элемент
q^.Next := head^.Next; вставляем его в голову списка
head^.Next := q; в head^.Next адрес головы списка
Repeat
New(q); формируем очередной элемент
Write(`Очередное число: ');
ReadLn(q^.Inf); вводим его информационную часть
If (q^.Inf=0) если ввели 0,
Then Break; то выходим из цикла ввода
head^.Inf := head^.Inf + 1; увеличиваем счетчик элементов на 1
q^.Next := head^.Next; вставляем элемент в голову списка
head^.Next := q; в head^.Next адрес головы списка
Until (q^.Inf = 0);
End;
Procedure Vyvod_spisok; процедура вывода списка
Begin
q := head^.Next; текущую ссылку - на первый элемент
While (q <> Nil) Do пока не конец списка
Begin
Write(q^.Inf:5); выводим очередной элемент
...Подобные документы
Логические конструкции в системе программирования Паскаль. Команды языка программирования, использование функций, процедур. Постановка и решение задач механики в среде системы Паскаль. Задачи статики, кинематики, динамики решаемые с помощью языка Паскаль.
курсовая работа [290,9 K], добавлен 05.12.2008Изложение основ информатики, вычислительной техники и технологии программирования на языке Паскаль. Эволюция средств вычислений. Классификация программного обеспечения ЭВМ. Кодирование информации в ЭВМ, системы счисления, принципы программирования.
учебное пособие [1,4 M], добавлен 25.12.2009Международный стандарт на язык программирования Паскаль. Приемы объектно-ориентированного программирования в Турбо Паскале. Символы языка, его алфавит. Этапы разработки программы. Понятие алгоритмов и алгоритмизации. Структура программ на Паскале.
курсовая работа [29,8 K], добавлен 28.02.2010Особенности программирования на языке Паскаль в среде Турбо Паскаль. Линейные алгоритмы, процедуры и функции. Структура данных: массивы, строки, записи. Модульное программирование, прямая и косвенная рекурсия. Бинарный поиск, организация списков.
отчет по практике [913,8 K], добавлен 21.07.2012История и основы структурного программирования в среде Turbo Pascal. Работа с различными типами данных. Операторы языка. Работа с символьными и строковыми переменами, одномерным, двумерным массивами. Классификация компьютерных игр. Игры на языке Паскаль.
курсовая работа [28,8 K], добавлен 06.05.2014Язык программирования Турбо Паскаль. Запись алгоритма на языке программирования и отладка программы. Правила записи арифметических выражений. Стандартное расширение имени файла, созданного системным редактором. Составной оператор и вложенные условия.
курсовая работа [75,0 K], добавлен 21.03.2013Изучение символьных и строковых типов данных, алгоритма задачи на языке программирования Паскаль. Описания получения и установки отдельного символа строки, изменения регистра символов. Анализ создания и просмотра файла, поиска и сортировки информации.
курсовая работа [440,7 K], добавлен 13.06.2011Основные сведения о системе программирования Турбо Паскаль. Структура программы на Паскале и ее компоненты. Особенности и элементы языка Турбо Паскаль. Порядок выполнения операций в арифметическом выражении, стандартные функции и оператор присваивания.
лекция [55,7 K], добавлен 21.05.2009Освоение технологии структурного программирования и применения стандартных методов работы с одномерными массивами при разработке и создании программы на языке Турбо Паскаль. Разработка программы методом пошаговой детализации с помощью псевдокода.
реферат [276,9 K], добавлен 27.02.2008Сущность понятия "тип данных". Объектно-ориентированный стиль программирования. Простые типы данных в языке Паскаль: порядковые, вещественные, дата-время. Булевский (логический) тип. Синтаксис определения ограниченного типа. Регулярные типы (массивы).
реферат [24,1 K], добавлен 01.12.2009Изучение истории создания языка Турбо-Паскаль, важнейшего инструмента для обучения методам структурного программирования. Анализ меню управления всеми ресурсами интегрированной инструментальной оболочки, зарезервированных слов, символьных переменных.
презентация [989,7 K], добавлен 06.12.2011Программирование на языке Паскаль: алфавит, решение задач, простейшие программы, разветвляющие программы, циклические программы, ввод-вывод, массивы, подпрограммы, строковые данные, записи, файлы, использование библиотеки CRT, графика в Паскале.
учебное пособие [211,1 K], добавлен 30.03.2008Рассмотрение общих сведений и уровней языков программирования. Ознакомление с историей развития, использования языков программирования. Обзор достоинств и недостатков таких языков как Ассемблер, Паскаль, Си, Си++, Фортран, Кобол, Бейсик, SQL, HTML, Java.
курсовая работа [759,5 K], добавлен 04.11.2014Особенности способов описания языков программирования. Язык программирования как способ записи программ на ЭВМ в понятной для компьютера форме. Характеристика языка Паскаль, анализ стандартных его функций. Анализ примеров записи арифметических выражений.
курсовая работа [292,0 K], добавлен 18.03.2013Сравнительный анализ языков программирования высокого уровня Си и Паскаль. Реализация алгоритма обработки данных. Тестирование и отладка программы или пакета программ. Структура программы на языке Турбо Паскаль. Указатели и векторные типы данных.
курсовая работа [233,5 K], добавлен 14.12.2012Программирование нестандартных функций, задач оптимизации, дифференциального уравнения и аппроксимации с помощью языка Паскаль. Алгоритм и программа операций над матрицами. Нахождение значения корней нелинейного уравнения по методу половинного деления.
курсовая работа [1,1 M], добавлен 12.08.2011Общая характеристика языков программирования. Описание языка Паскаль: основные субъекты языка; структура Паскаль-программы; типизация и объявление данных. Операторы присваивания и выражения. Структурные операторы, организация ветвлений и циклов.
дипломная работа [276,6 K], добавлен 26.01.2011Паскаль как язык профессионального программирования, который назван в честь французского математика и философа Блеза Паскаля, история его разработки и функциональные особенности. Задача с использованием двумерного массива, составление блок-схемы решения.
контрольная работа [819,0 K], добавлен 12.03.2014Использование скриптового языка программирования для разработки web-приложений (сценариев). Изучение основ объектно-ориентированного программирования в языке PHP. Ознакомление со специальными методами для работы с классами. Назначение интерфейсов.
контрольная работа [25,1 K], добавлен 14.03.2015Описание конструкций языка программирования Паскаль, обеспечивающих ветвление. Организация циклических процессов. Создание программы для ввода последовательности вещественных чисел до появления 0, расчет среднего арифметического данной последовательности.
лабораторная работа [189,8 K], добавлен 17.04.2012