Тема: Програмування. Основні етапи розробки прикладних програм
Вид материала | Документы |
- Текст програми це набір інструкцій (команд), які можуть бути виконані комп'ютером., 221.57kb.
- Тема: Робота в середовищі програмування. Запуск програм на виконання, 202.65kb.
- 1. Мови програмування (процедурні, візуальні, специфікацій). Концепція інструментального, 757.76kb.
- Програма Комплексного вступного іспиту на окр «Спеціаліст», 814.3kb.
- Називається комплекс програмних та мовних засобів, які використовуються для створення, 149.17kb.
- План лекції Тема І основні питання. Актуальність теми Лекційний матеріал Педіатрія, 473.4kb.
- Тема. Основні етапи розв’язування прикладної задачі з використанням комп’ютера. Інформаційна, 85.92kb.
- Розробка програми (робочого плану) моніторингу світового ринку готельних та ресторанних, 33.83kb.
- Структуризація програми. Поле, метод, класс, файл, проект. Об’єктне програмування., 327.95kb.
- Рекомендації з розробки навчальних та робочих програм (зі змінами І доповненнями) львів, 500.26kb.
Наприклад
Var
x1: integer; x2: char; x3: boolean; x3: rainbow;
…
x1: =32766;
x2: =’A’;
x3: =true;
x4: = red;
inc (x1); { x1=32767 }
inc (x1,2); { x1=-32767 }
dec (x3,2); { x3=true }
dec (x4); { x4=magenta }
4.Структурокані типи даних:
Раніше розглядалися скалярні дані. Це означає, що здійснювалася обробка неподільних значень деякого типу. Навіть, якщо в програмі викликається багато скалярних величин одного типу, але вони не є незалежними, то їх не можна вважати деякими структурами даних. Структурування передбачає об’єднання складених даних в єдині складені структури, що обробляються і розміщуються в пам’яті як одне ціле. Одним із способів структурування є формування так званих регулярних структур даних. До них відносять масиви, рядки, множини.
а) Регулярні типи – масиви
Масиви – структури даних, які є об’єднанням в одне ціле деякої фіксованої кількості однотипних елементів. Оголошуються масиви за допомогою службового слова array, після якого вказується розмір масиву, кількість елементів, а також тип самих елементів масиву.
TYPE<ідентифікатор типу >= ARRAY[<діапазон індексів>,<діапазон індексів >,…] OF<тип елементів > ;
В якості діапазонів індексів можуть викликатися інтервали одного із дискретних типів.
Кількість діапазонів визначає розмірність масиву:
1 діапазон – одновимірний масив;
2 діапазони – двовимірний ( таблиці, матриці);
п діапазонів – п-вимірний.
Діапазони індексів задаються аналогічно інтервальним типам, через .. . В якості типу елементів може бути виключно один із стандартних типів або будь-який раніше оголошений скалярний чи структурний тип даних.
Наприклад
Type
rainbow =(red, orange, yellow, blue, dark blue, magenta);
vector = array [1..3] of real;
mas1 = array[‘A’..’Z’] of byte;
mas2 = array[1..8,’A’..’H’] of byte;
mas3 = array[false,true, red..yellow] of char;
mas4 =array[-100..-50] of vector;
Оголошення змінних типу масив може здійснюватися або використанням ідентифікаторів раніше описаних
x:= mas1; y:= mas4;
або явним чином
a: array[1..26] of byte;
Доступ до елементів масиву для надання їм значень або навпаки для отримання їх, здійснюється через складену ідентифікацію, для цього задається ідентифікатор масиву, а в квадратних дужках задається значення відповідних ідентифікаторів.
В пам’яті під змінні масивних типів відводяться поля, розмір яких у байтах є сумою розмірів всіх елементів.
У випадку багатовимірних масивів елементи їх розміщуються послідовно в пам’яті в порядку задання розмірностей.
Якщо масиви використовуються в якості типізованих констант, то їх константні значення задаються переліком значень всіх елементів по кожній розмірності, елементи 1-ї розмірності обмежуються дужками. Якщо ж більше ніж одна, то кожен наступний рівень передбачає зовнішньою парою дужок.
б) Регулярний тип – рядки символів:
Структура даних, елементи якої є символами у Pascal є рядки символів. По способу організації і розміщення у пам’яті подібні до масивів. Їх відносять до однієї групи складених типів – регулярних.
Рядок – це деякий набір однотипних елементів. Проте їх кількість може змінюватися, але не перевищує деякої фіксованої межі
В ранніх версіях Pascal рядки навіть оголошувалися як масиви( упорядковані масиви символів).
В Turbo Pascal рядки символів оголошуються службовим словом STRING. При оголошенні може задаватися граничне значення довжини рядка, що слідує після слова string у квадратних дужках.
Це значення може лежати в межах від 0 до 255.
Реальна довжина рядка може бути меншою, але не більшою. Якщо така ситуація виникає, то залишок, що перевищує граничну довжину, втрачається.
Величини записуються в апострофах.
Наприклад
Var
S1: string;
S2: string[6];
…
S1:=’ABCDEFGH’;
S2:=S1; {S2=’ABCDEF’}
Для того, щоб апостроф сам став символом, а не лише його обмеженням, він повинен бути записаний двічі.
В пам’яті під рядки символів відводяться ділянки, кількість байт яких на одиницю більше від вказаної граничної довжини. Додатковий байт, який має нульовий номер, містить символ, код якого дорівнює реальній межі рядка. Якщо реальна менша від граничної, відведенні, але не використанні байти містять пусті символи, код яких дорівнює нулю.
Реальну довжину рядка легко змінити, при цьому інформація, яка знаходиться в хвості ділянки не втрачається і відновлюється, якщо повернутися до початкової довжини.
Рядки по структурі подібні до масивів, то можна легко оперувати символами рядка, користуючись індексацією елементів. Нульовий байт відповідає довжині.
При роботі із окремими елементами рядка слід пам’ятати, що цей елемент матиме типу char і для окремих стандартних підпрограм, що працюють з рядками він буде незастосовний.
Зауваження Рядок з одного символу і окремий символ типу char не одне і теж.
Для роботи із рядками символів, крім операцій індексного доступу можуть виконуватися операції об’єднання та порівняння та ряд дій, що реалізуються стандартними процедурами і функціями.
Об’єднання (конкатенація).
Конкатенація – приєднання одного рядка в кінець іншого.
Наприклад
S:=’і’ + ‘ стань’ + ‘ зіркою’; {і стань зіркою}
Якщо результат конкатенації перевищує граничну довжину, то надлишок просто ігнорується.
Операція порівняння
Два рядки рівні, якщо вони мають однакову кількість елементів і елементи відповідні рівні.
Наприклад
S1: string;
S2:string;
…
S1:= ‘ABCD’; {S1=S2}
S2:= ‘ABCD’;
Порівняння рядків порівнюється по-байтно, починаючи з першого символа.
в) Регулярний тип – множини
Множини і тип даних теж відносяться до регулярних складених типів. Це означає, що елементи таких структур даних будуть однотипні значення (цілі числа, символи, перелічувальні типи). На відмінну від масивів, де кількість елементів є фіксованою і незміною, множини можуть змінювати свій склад, проте кількість елементів не може перевищувати деякого фіксованого значення. І масиви, і рядки можуть мати декілька однакових елементів, у множині всі елементи різні.
Оголошення множини, при доповненні стандартних слів set of, після яких вказується ідентифікатор елементів множини. В якості базових типів можуть бути лише порядкові типи і кількістю елементів до 256. це цілі byte, shorting, символи char, логічні boolean.
Наприклад
Var
A: set of byte;
B: set of 0..100;
C: set of char;
D: set of rainbow;
Значення множинних величин задається в парі квадратних дужок, переліком через кому або інтервалом.
Наприклад
A:=[109,100,0,5..50];
B:=[100,0..99];
C:=[‘A’,’Z’];
D:=[red];
Множини можуть бути пустими[ ].
В пам’яті множини представляються у вигляді чисел достатньо великого розміру. Кожне із цих чисел в своєму подвійному записі матиме одиничний біт у позиції, що відповідає присутньому елементу. Таким чином множини займають у пам’яті 256 бітів і до 32 байт.
Якщо базовий тип є перелічувальний або інтервальний із меншою ніж 256 елементів, то і відповідне поле в пам’яті буде менше. Заданя перелічувальних типів визначає порядок бітів, що відповідають кожному елементу.
5.Комбіновані структури даних.
а)Записи
Масиви, рядки, множини давали складені структури даних, елементи яких були одного і того ж типу. Кількість елементів в них могла б бути різною. В масивах фіксованою, в рядках і множинах могла б змінюватися, але тип був би спільним. Часто виникає проблема у формування структур даних, елементи яких мають різний тип.
Об’єднання цих типів в одну структуру
Оголошуються записи за допомогою слова record. Після нього слідує перелік окремих елементів запису. Елементи описуються через ідентифікатор і тип, що розділюється двокрапкою.
В кінці запис закривається службовим словом end.
TYPE
<ім’я типу запису> = RECORD
<ідентифікатор1>: <тип поля>;
<ідентифікатор2>: <тип поля>;
...
END;
Наприклад
Type
Student = record
Name: string;
Yy, mm, dd: word;
Pol: (female, male);
Educ: (state, pay);
Usp:real;
End;
Під величини в пам’яті відводиться, розмір якого дорівнює сумі розмірів кожного поля.
Оскільки записи є комбінаціями різних полів, то доступ до окремого поля повинен здійснюватися при допомозі складеної ідентифікації, кожне поле має своє ім’я.
Якщо весь запис позначається деяким ідентифікатором деякої змінної, то кожне ім’я поля має вигляд
<ідентифікатор запису>.<ідентифікатор поля запису>
Наприклад
a.name , a.year, a.pol, a.educ
Враховуючи, що запис є комбінацією різних типів, можна будувати записи із записів.
Наприклад
Дату народження можна оголосити не трьома цілими числами, а записом трьох чисел.
Type
Date = record
Yy: integer;
Mm, dd: byte;
Таким чином ми отримуємо запис в записі.
Для доступу до окремих полів дати народження, в цьому випадку теж використовуються складені ідентифікатори.
Враховуючи скомбінованість структури, ввід і вивід даних можливе лише по окремих полях.
Якщо запис містить невелику кількість полів, то використання складених ідентифікаторів не є обтяжливим, але коли полів багато і щоразу використовується звернення до більшості з них, то використання загального імені запису в кожному випадку вимагає конструктивної роботи по набору тексту. Тому в таких випадках використовуються спеціальні оператори приєднання або оператори надзапису.
WITH <ім’я запису>DO <оператор над полями>;
Наприклад
With a do
Begin
Readln(name);
With date born do
Readln(yy, mm, dd);
Readln(usp);
Операції над записами зводяться до операцій відношення до порівняння на рівність і не рівність.
Рівні – записи, в яких структура і значення всіх полів однакові.
Наприклад
Програма формування бази даних про студентів у вигляді масиву із п записів.
Type
Student = record
{}
end;
var
a: array[1..n] of student;
i, j: byte;
begin
for i:=1 to n do
with a[i] do
begin
writeln(‘введіть ім’я’);
readln(name);
with date born do
begin
writeln(‘введіть дату народження’);
readln(yy,mm,dd);
end;
writeln(‘введіть стать: 0-жін; 1-чол’);
readln(j);
if j=1 then pol:=male else pol:=female;
writeln(‘введіть форму навчання: 0-держ; 1-плат’);
readln(j);
if j=1 then educ:=pay else educ:=state;
writeln(‘введіть успішність’);
readln(usp);
end;
Формування баз даних має свої переваги і недоліки. До переваг відносять те, що масив розміщується у швидкій оперативній пам’яті, а це значно зменшує час роботи.
Крім того, розміри масивів є фіксованими, а отже збільшити кількість записів не вдасться.
Набагато зручніше реалізовувати бази даних у вигляді файлів.
б) Записи з варіантами
Часто бази даних повинні містити інформацію, структура якої залежить від значень окремих полів.
Наприклад
В базі даних про студентів для хлопців актуальним може бути відношення до військової служби (придатний, непридатний) і зріст (в танкові війська до 175 см), а для дівчат інтерес може мати колір волосся, очей, улюблена косметика.
Таким чином, якщо поле pol має значення male, то запис повинен мати два додаткових поля (армія, зріст). Якщо ж pol дорівнює female, то потрібно три додаткові поля. Решта ж полів мають бути однакові.
Для реалізації таких комбінованих типів використовуються записи із варіантними частинами. Вони будуються подібно до звичайних записів, але використовують оператор case.
Зауваження
- Варіантна частина у записі може бути лише одна і лише в кінці. Службове слово end є спільним для конструкції record і варіантної частини.
- ключ варіантної частини повинен бути визначеним певним типом. Для кожного значення ключа задається перелік полів запису, кожному полю вказується тип. Якщо кількість полів відповідно значення ключа більша ніж одне, то ці поля обмежуються парою дужок.
Величини типу записів з варіантами розміщується так само, як і звичайні записи, розмір відповідає максимуму сумарних розмірів всіх полів серед всіх варіантів. Таким чином запис студент матиме розмір 51+(2+1+1)+1+1+6+1+1.
Таким чином варіантна частина запису пишеться на одній ділянці, при цьому на цьому місці можуть бути різні дані в залежності від значення ключа, тому коректність даних залежить від самого програміста.
Ключ визначає ніби маску, яка накладається на ділянку пам’яті і інтерпретує певну кількість байтів, як значення певного типу
Окрім структури і збереження в пам’яті записи із варіантами всі решта дії аналогічні звичайним записам.
Наприклад
База даних про студентів
Var
a: array[1..n] of student;
i, j: byte;
begin
for i:=1 to n do
with a[i] do begin
readln(name);
with date born do
readln(yy, mm, dd);
readln(j);
if j=1 then educ:=pay else educ:=state;
readln(usp);
writeln(‘введіть стать: 0-жін; 1-чол’);
readln(j);
if j=1 then pol:=male else pol:=female;
case pol of
male : begin
writeln(‘0-непридатний, 1-придатний’);
readln(j);
if j=1 then army:=yes else army:=no;
writeln(‘зріст’);
readln(hight);
end;
female: begin
writeln(‘волосся: 0-чорне, 1-шатенка, 2-блондинка’);
readln(j);
case j of
0: hair:=black;
1: hair:=shaten;
2: hair:=blond;
end;
writeln(‘очі: 0-чорні, 1-зелені, 2-сині, 3-карі’);
readln(j);
case j of
0: eyes:=black;
1: eyes:=green;
2: eyes:=blue;
3: eyes:=brown;
end;
writeln(‘косметика’);
readln(cosmetics);
end;
end;
end;
end.
Пошук потенційних танкістів.
For i:=1 to n do
With a[i] do
If (pol=male) and (date born.yy<1985) and (date born.mm<11) and (usp<3) and (army=yes) and (hight<=175) then writeln (name, ‘танкіст’);
End.
ТЕМА : Програми обробки структурованих типів.
- Приклади задач з масивами
- Знайти середнє арифметичне додатніх і від’ємних елементів масиву цілих чисел.
- Знайти середнє арифметичне додатніх і від’ємних елементів масиву цілих чисел.
Var
a: array[1..20] of integer;
S1, S2, i, i1, i2: integer;
x1,x2: real;
begin
for i:=1 to 20 do
begin
write (‘?’); {ввід масиву}
readln(a[i])
end;
for i:=1 to 20 do
begin
if a[i]>0 then begin S1:=S1+a[i]; i1:=i1+1 end;
if a[i]<0 then begin S2:=S2+a[i]; i2:=i2+1 end;
end;
if i1>0 then begin x1:=S1/i1; writeln(x1)
else writeln(‘+немає’);
if i2>0 then begin x2:=S2/i2; writeln(x2) else writeln (‘ – немає’);
end
Показаний приклад показують, що вибір індекса масиву залежить від типу оброблюваних даних. Деколи зручніше організувати індекси не цілочисельні, а за допомогою символів чи якогось перелічувального типу. Такі масиви в якості своїх значень можуть зберігати в кількості елементів такого символьного або перелічувального типу.
При обробці багатовимірних масивів використовуються вкладені оператори циклу. При цьому слід пам’ятати: самі зовнішні цикли відповідають самому першому індексу, а внутрішні останні.
Перетинання тіл циклів не призводить до синтаксичної помилки, а лише дасть неправильний результат.
- Стандартні підпрограми обробки рядків
Pascal має набір стандартних підпрограм обробки рядків: функції, процедури.
Функції на відміну процедур мають результат деякого типу і можуть бути використані в якості компонентів виразу.
Процедури являють собою дію. Вони будуть окремими командами програми. Результат обертатиметься у вигляді параметрів.
а) Функція визначення довжини
Параметром (аргументом) буде рядок символів, результатом – ціле число типу byte.
LENGTH(‘<рядок>’)=<довжина рядка>;
Вона не може змінювати довжину рядка.
б) Функція виділення частини рядка
якщо з деякого рядка треба виділити підрядок, використовується функція copy.
COPY (<ідентифікатор рядка>,<позиція, з якої відбувається крпіювання>,<довжина потрібного фрагменту>);
Очевидно, що значення параметру не повино перевищувати реальну довжину рядка.
i – номер позиції, j- довжина фрагменту. Значення виразу i+j-1 – перевищує реальну довжину, то відбуватиметься виділення лише наявної частини рядка. Фрагмент буде коротшим ніж j символів.
Наприклад
Перевірити чи введений рядок є паліндромом.
Var
S1,S2: string;
i: byte;
begin
writeln(‘’);
readln(S1);
S2:=”;
For i:=length(S1) downto 1 do
S2:=S2+copy(S1,I,1);
If S1=S2 then writeln (‘’) else writeln (‘’);
End.
в) Функція знаходження номера позиції
Ця функція знаходить номер позиції, з якої починається перше входження деякого слова в рядок. Якщо це слово в рядку не знайдено, то буде надруковано число 0.
POS (<шукане слово>,<ідентифікатор рядка>);
Наприклад
Const R=’Севастополь’;
WORD=’сто’;
Var P: byte;
Begin
P:=pos(WORD,R); {P=5}
Writeln(P) ;
End.
г) Процедура вставлення слова
Ця процедура вставляє деяке слово в рядок, починаючи з вказаної позиції.
INSERT(<слово, яке треба вставити>,<ідентифікатор рядка>,<позиція>);
Наприклад
Var
Poz: integer;
R,WORD: string;
begin
Poz:=20; {Мова програмування Turbo Pascal}
R:=’Мова програмування Pascal’;
WORD:= ‘Turbo’;
Insert(WORD,R,Poz);
Writeln(R);
End.
д) Процедура видалення
Процедура видалення знищує слово, яке починається з вказаної позиції і має задану довжину в рядку.
Наприклад
Var
R: string;
N,Poz: integer;
Begin
R:= ‘Мова програмування Turbo Pascal’;
Poz:= 1;
N:=19; {Turbo Pascal}
Delete(R,Poz,N);
Writeln(R);
End.
е) Функція обєднання рядків
обєднання рядків може проводитися не лише при доповню вального знака операції +, а і функцією concat. Ця функція може містити довільну кількість аргументів типу string.
CONCAT (<рядок1>,<рядок2>,…);
Якщо сумарна довжина результуючого рядка перевищує 255, то надлишок ігнорується.
Наприклад
В рядку символів замінити всі ланцюги ABC на xy.
Var
S1, S2: string;
i: byte;
begin
writeln(‘’);
readln(S1);
S2:=S1;
For i:=1 to length(S2) do
If copy(S1,i,3)=’abc’ then
Begin
Delete(S2,i,3);
Insert(‘xy’, S2,i);
End;
Writeln(S1);
Writeln(S2);
End.
З рядка символів вилучити всі повторення підряд однакових символів крім першого.
Var
S1, S2: string;
i: byte;
begin {}
S2:=S1;
For i:=1 to length(S2) do
If copy(S2,i,1)=copy(S2, i+1,1) then
Begin
Delete(S2,i+1,1);
i:=i-1;
end;
writeln(S1);
writeln(S2);
end.
- Операції над множинами
Над множинами можуть виконуватися наступні дії:
а) Обєднання (додавання)
Виконується над множинами одного базового типу.
Наприклад
A:=[1,2,3] B:=[3,4,8] C:=A+B { C=[1,2,3,4,8] }
Виконання операції додавання фактично є побітовою операцією диз’юнкції.
б) Перетин (множення множин)
Результатом є спільна частина двох множин.
Наприклад
[1,2,3]*[3,4,8] =[3]
[1,2,3]*[ ]= [ ]
Виконання операції множення фактично є побітовою кон’юнкцією.
в) Віднімання множин
Результат віднімання деякої множини В від множини А будуть всі елементи А, яких немає в множині В.
Наприклад
[1,2,3]-[3,4,8]=[3]
В памяті операція віднімання фактично є
Це побітова операція виключення або одиничними бітами у зменшуваному.
Крім операцій додавання, множення, віднімання над множинами виконуються логічні операції порівняння та належності.
Множини можуть порівнюватися на рівність та нерівність.
г) Операція належності
Дає істиний результат, якщо деякий елемент належить множині. Операція хибна в іншому випадку.
Наприклад
[1] in [3,4,8] = false
[1] in [1,2,3]=true
Формування множини безпосередньо з клавіатури і вивід їх на екран неможливо, оскільки стандартні процедури вводу-виводу не допускають параметрів множини так як і перелічувального. Але ці дії легко реалізувати за рахунок операції обєднання та перевірки належності in для виводу.
Звичайно базовий тип множини в цьому випадку повинен бути допустимим для процедур вводу-виводу.
Наприклад
Var A:=[ ]; A:=[ ];
A: set of byte; repeat readln(x);
i, x: byte; readln(x); while x<>0 do
… A:=A+[x]; begin
A:=[ ]; until x=0; A:=A+[x];
for i:=1 to n do readln(x);
begin end.
readln(x);
A:=A+[x]
end;
Варіант із циклом repeat until завершує формування множини із записанням в неї нульового елемента, тобто в будь-якому випадку множина матиме хоча б один елемент.
Варіант із циклом while do припиняє формування множини без введення елемента 0 в неї, тобто може отриматися пуста множина.
Для виводу елементів множини можна скористатися операцією in.
Наприклад
For i:=1 to 255 do
If I in A then writeln(i);
В деякій установі є k працівників, кожен з них має два вихідні в тижні, але всі різні. Перевірити чи забезпечується неперервність виробничого процесу протягом тижня.
Якщо результат множення для кожного працівника дасть пусту множину, то це відповідає неперервності робочого процесу. Якщо ж результат міститиме хоч один день, це і відповідає загальному вихідному.
Type
Wwekend = set of week;
Week = 0..6;
Workers = array [1..6] of integer;
Var
k, i, j: byte;
a: workers;
c:weekend;
begin
c:=[0..6];
for i:=1 to 6 do
begin
writeln(‘введіть номери вихідних днів’, і , ‘-го працівника’);
readln(j,k);
a[i]:=[j,k];
c:=c*a[i];
end;
if c=[ ] then writeln(‘все добре’)
else writeln(‘є повний вихідний’);
end.
В даній програмі, якщо множина не надавати початкового значення, то вона приймається пустою, тому попередньо до формування множини С їй потрібно надати початкове значення, що рівне повній множині.
ТЕМА : Підпрограми
Структурне програмування передбачає представлення програм у вигляді послідовності викликів підпрограм. В свою чергу останні теж можуть структуруватися на елементарні підпрограми.
Поняття підпрограми означає логічно-завершальну програму компоненту, що виконує деяку частину алгоритму.
Ford-RAN були звичайними частинами програми. Вони не мали механізму передачі параметрів і користувалися загальновживаними змінними.
Використання механізму передачі параметрів (МПП) дозволило зробити окремі підпрограми більш незалежними. Це полегшило використанні програми та її відланку.
В Pascal є два види підпрограм:
1. Процедури являють собою дію, тому їх можна використовувати в якості окремого оператора в розділі операторів програми.
2. Функції являють собою значення певного типу, крім цього вони можуть використовувати деяку дію, але значення їх є головним. Тому функції використовують як окремі оператори у виразах.
Оголошуються процедури і функції у розділі оголошень, причому оголошення
Формальне оголошення процедур має вигляд:
PROCEDURE <ім’я> (<список формальних параметрів>);
<розділ оголошень>;
<тіло процедури>;
Ім’я процедури формується згідно з правилами побудови ідентифікаторів у Pascal.
Список параметрів містить перелік величин із заданням їхнього типу, що можуть передаватися у підпрограму (вхідні параметри) або повертатися із підпрограми (вихідні).
Розділ оголошень містить описи всіх об’єктів, що використовуються лише у цій підпрограмі.
Тіло підпрограми містить оператори, що об’єднуються операторними дужками.
FUNCTION (<список формальних параметрів> :)<тип результату>;
<розділ оголошень>;
<тіло функції>;
На відмінну від процедур у функції обов’язково задається тип її значення. В якості типу результату можуть бути скалярні типи, рядки, множини, вказівники.
В розділі операторів обов’язково повинен бути присутній хоча б один оператор присвоєння ідентифікатору функції деякого значення, що і буде результатом функції.
Наприклад
Процедура і функція, що обчислюють суму елементів масиву цілих чисел.
CONST n=5;
TYPE
masiv=array[1..n] of integer;
PROCEDURE P_SUMA(a: masiv; m:integer; var suma: integer);
VAR
i: byte;
BEGIN
suma:=0;
for i:=1 to m do
suma:=suma+a[i]
END;
FUNCTION F_SUMA(a:masiv; m:integer): integer;
VAR
i: byte;
s: integer;
BEGIN
s:=0;
for i:=1 to m do
s:=s+a[i];
F_SUMA:=s;
END;
Процедура має три параметри: два вхідні – масив а і кількість т і один вихідний – сума.
Розділ оголошень локальних містить і типу byte.
Тіло процедури складається з двох операторів
Через значення функції типу integer локальне оголошення містить дві змінних. Тіло функції містить оператор присвоєння.
При фактичному виклику оголошених підпрограм результат можна отримати таким чином.
VAR
aa: masiv;
c, j: integer;
BEGIN
for j:=1 to n do
readln(aa[i]);
P_SUMA (aa, n, c);
c:= F_SUMA(aa,n);
Механізм передачі параметрів
При звернені до підпрограми, їм можуть передувати в якості вхідних даних деякі значення, крім того деякі вхідні дані можуть змінювати своє значення в тілі підпрограми і можуть повертатися в якості вихідних.
В Pascal використовується три види параметричних підпрограм;
1. Параметри-значення.
2. Параметри-змінні.
3. Без типові параметри.
Задання виду параметрів здійснюється формальним оголошенням заголовку підпрограм.
- Параметри-значення
Параметри-значення виступають в якості вхідних параметрів, тобто їх значення передається у підпрограму і в процесі її виконання не може змінюватися.
Оголошуються такі параметри шляхом переліку формальних ідентифікаторів та заданням їхнього параметру.
Оскільки значення таких параметрів не змінюється, то при фактичному виклику підпрограми в якості фактичних параметрів-значень можуть бути змінні, константи, зображення певного типу.
Наприклад
Програма, що реалізує операції над комплексними числами.
TYPE
Complex=record
Re, Im:real;
END;
PROCEDURE SUMA (a, b: complex; var c:complex);
BEGIN
c:=a.Re +b.Re;
c:=a.Im+b.Im;
END;
BEGIN
…
a.Re:=2;
a.Im:=2;
b.Re:=1;
b.Im:=-2;
SUMA (a,b,c);
END.
При формальному оголошенні процедури. Перші два параметри є параметрами-значеннями.
В тілі процедури описаний алгоритм у вигляді послідовності операторів. В програмі оголошено три змінні a, b, c, яким надаються двом із них.
При фактичному виклику процедури сума їй передаються в якості вхідних параметрів значення змінних a,b, результат змінна с.
В якості фактичних параметрів можуть використовуватися будь-які ідентифікатори типу complex.
Фактичні параметри можуть бути будь-які об’єкти програми, тип яких відповідає типу формальних параметрів.
- Параметри-змінні
Виступають в якості вихідних параметрів. Це означає, що їх початкове значення може змінюватися у тілі підпрограми і ця зміна повертається в точку виклику підпрограми.
Таким чином при фактичному виклику підпрограми в якості фактичних параметрів змінних можуть використовуватися лише змінні.
Оголошуються парамерти змінних при допомозі var і переліку ідентифікаторів та задання їх типу, якщо підпрограма має декілька параметрів змінних при формальному оголошенні, кожному з них повинен передувати var.
В попередньому прикладі параметром змінної була змінна с.
Наприклад
сумування дійсних чисел.
PROCEDURE SUMA_RITH (a, b:real; var s:real; var r:real);
BEGIN
s:=a+b;
r:=a-b;
END;
VAR x, y, z, t:real;
BEGIN
x:=5; y:=2;
SUMA_RETH(x,y,z,t);
SUMA_RITH(4,3,z,t);
END;
В одному прикладі є два параметри змінних, які формально позначенні s та r, при фактичному виклику їх використовують як змінні t, z.
Параметри змінних можуть виконувати функцію вхід і вихід параметрів одночасно. Результат суми зберігається в першому аргументі, а різниця в другому.
PROCEDURE P (var a:real; var b:real);
var x:real;
BEGIN
x:=a;
a:=a+b;
b:=x-b
END;
VAR x,y:real;
BEGIN
x:=5; y:=3;
P(x,y);
END;
Якщо параметр-змінна виконує функцію вхідного параметра, то при фактичному виклику можна використовувати лише змінні.
В даній процедурі оголошена своя змінна х для тимчасового збереження одного із вхідних даних, така змінна – локальна і використовується лише у межах даної підпрограми.
Час її існування при виконані програми теж є тимчасовим, лише під час виконання підпрограми.
В зовнішній підпрограмі x,y – глобальні змінні. Вони доступні в межах всієї програми і всіх для її підпрограм.
Якщо в підпрограмі є однойменні локальні і глобальні змінні, то уникнення конфлікту імен здійснюється завдяки так званому екрануванню ідентифікаторів, тобто в межах кожної підпрограми доступним є лише свій локальний об’єкт. Він перекриває однойменні глобальні об’єкти, а глобальної змінної х доступу немає, хоча легко доступна глобальна змінна y.
- Без типові параметри
Можуть виконуватися, в якості вхідних і вихідних як параметри змінних, але на відмінну від них, не вимагають задання типу. При фактичному виклику на їх місці може стояти змінна будь-якого типу (найчастіше використовують вказівними).
Такі параметри використовують тоді, коли розміри ділянки пам’яті, де зберігається значення параметрів є невизначеним наперед. В цьому випадку передається не вся комірка, а адреса її початку, тобто вказівник на неї.
Оголошуються без типові параметри при допомозі var, після якого іде перелік ідентифікаторів без вказання типу.
При фактичному виклику підпрограм із без типовими параметрами найчастіше використовуються змінні вказівного типу, що є вказівником комірки з даними.
Цими параметрами можуть бути лише змінні.
Механізм виклику підпрограм
Кожна підпрограма є окремою командою в головній програмі. При зверненні до підпрограми відбувається передача управління в частину виконуваного коду програми, який відноситься до цієї підпрограми. Після завершення підпрограми відбувається повернення в основну програму.
Для цього спеціальному сегменту підпрограми, який називається сегментом стеку, записуються адреси точок повернення після виконання програми.
В цьому сегменті розміщуються всі локальні змінні даної підпрограми, а також її фактичні параметри. Це означає, що звертання до багатьох підпрограм з деякою кількістю фактичних параметрів змінних вичеркує сегмент стеку, тому потрібно контролювати цю ситуацію, бо програма перерве своє виконання при переповненому стеку.
Два байти на адресу сегменту і два байти на зміщення в ньому.
Рекурсія
Використання підпрограми із механізмом передачі параметрів дозволяє реалізувати такий спосіб повторення як рекурсія деякого алгоритму за рахунок звернення до самого себе.
Рекурсія – такі підпрограми, які в самому тілі містять фактичний виклик самої себе.
« А этот глист страдал глистами, которые глистами мучались сами».
При рекурсивних викликах, очевидно потрібно забезпечити деяку умову зупинки, інакше таке повторення буде безкінечне. Для встановлення умови зупинки в тілі підпрограми використовується деяка перевірка, в залежності від результату якої відбувається ще один рекурсивний виклик, або ще одна зупинка дія, що відповідає зупинці рекурсії. Одним із фактичних параметрів буде входити в умову перевірки зупинки рекурсії. Якщо ж рекурсивна підпрограма без параметрів, то зупинити рекурсію можна лише або через глобальні змінні, або примусовою дією.
Наприклад
PROCEDURE P1;
BEGIN
Writeln(‘hello’);
P1;
END;
Це приклад необмеженої рекурсії, за рахунок процедури без параметрів.
VAR
n: integer;
PROCEDURE P2;
BEGIN
n:=n+1;
writeln(‘hello’);
if n<=3276 then P2 else writeln(‘stop”)
END;
BEGIN
…
n:=0;
P2;
…
END.
Дана процедура реалізує скінчену рекурсію з лічильником у вигляді глобальної змінної.
PROCEDURE P3 (n: integer);
BEGIN
Writeln(‘hello’);
If n<=3767 then P3(n+1) else writeln(‘stop’)
END;
BEGIN
P3(0)
END;
Цей приклад процедури з параметром.
Класичний приклад рекурсивного прикладу – це функція факторіал.
PROCEDURE p_fact(n: integer: var f: integer);
VAR f1: longint;
BEGIN
If n=0 then f:=1 else
begin
P_fact (n-1, f1);
F:=n*f1
end;
END.
FUNCTION f_fact(n:integer):longint;
BEGIN
If n=0 then f_fact:=1 else f_fact:=n*f_fact
END;
Розглянемо послідовність викликів для процедури. Нехай потрібно обчислити 3!.
При допомозі рекурсії можна реалізувати будь-який повторювальний алгоритм. Головне, щоб мали місце дві умови:
- Наявність умови зупинки, при якій деякому параметру рекурсії передається деяке значення рекурсії.
- чітко визначений алгоритм, при обчисленні кожного вищого рівня рекурсії через попередній рівень.
В загальному випадку рекурсивну систему можна описати так:
Нехай f(x,y), x, y – вхідні параметри алгоритму, реалізує повторювальний алгоритм. І є ще дві алгоритмічні функції з строго визначеним алгоритмом, тоді ця рекурсивна функцію можна побудувати так.
Таким чином, якщо вдасться певним чином побудувати алгоритм g(x) ma h(x, y, z), то на основі останнього співвідношення реалізується будь-який рекурсивний алгоритм. Для алгоритму обчислення факторіалу
g(x)=1
h(x, y, z) = y*f(y-1).
Підпрограми в якості параметрів інших підпрограм
Розглянуті раніше процедури та функції отримували в якості фактичних параметрів величини стандартних типів або структурованих, в ряді випадків виникає потреба передавати в якості параметра не лише дані, а й інші підпрограми.
При обчисленні деяких математичних величин використовуються різні функції. Замість того, щоб оголошувати в деякій підпрограмі багато різних функцій можна передавати їх в якості параметрів. В цьому випадку потрібно розширити множину відомих раніше типи даних і ввести так звані функціональний та процедурний типи.
Під функціональним або процедурним типом розуміється повна сукупність всіх функцій( процедур), які мають однаковий заголовок (інтерфейс).
Тіло кожної із функцій або процедур може бути відмінним, але всі вони повинні мати однакову кількість, порядок, тип параметрів, а для функцій тип результату.
Оголошуються функціональні (процедурні) типи в розділі type через службові слова procedure, function.
TYPE
<ім’я типу>=FUNCTION(<список формальних параметрів>):<тип результату>;
<ім’я типу>= PROCEDURE (<список формальних параметрів>);
Наприклад
TYPE
funct1= function(x:real): real;
func2=function(x, y:integer): boolean;
proc1=procedure(p:integer; var f:longint);
Перший тип являє собою сукупність всіх дійсних функцій від одного дійсного аргументу. Другий тип – множина логічних функцій від двох цілочисельних аргументів. Третій – множина всіх процедур з одним параметром змінної типу longint. Тепер можна оголосити змінні функціонального (процедурного типу. Їм можна присвоїти будь-яку функцію чи процедуру відповідного типу.
VAR
f1: funct1;
f2: funct2;
p1:proc1;
Присвоєння виду f1:=sin(x) не є коректним, оскільки змінна має тип function, а змінна х real.
0>