
- •Процедурно-орієнтоване програмування Організація підпрограм Поняття підпрограми
- •Організація підпрограм
- •Механізм передачі параметрів
- •Принцип локалізації
- •Концепція розподілу пам’яті
- •Способи передачі параметрів
- •Вказівники на функції
- •Розширені можливості використання підпрограм Функції з аргументами за замовчуванням
- •Перевантаження функцій
- •Шаблони функцій
- •Вбудовані функції
- •Рекурсія
Концепція розподілу пам’яті
При активізації програми в оперативній пам’яті ЕОМ створюється її образ, структура якого представлена на рис. 3.
-
16 Кб
Сегмент стека
(росте вниз )
64 Кб
Сегмент даних основної програми
образ
. . .
.exe- файлу
64 Кб
Сегмент коду основної програми
Рис. 3. Карта розподілу оперативної пам’яті комп’ютера при активізації програми
Область оперативної пам’яті, що її використовує програма, поділяється на декілька розділів -сегментів (зазвичай об’ємом 64 Кб), що служить для розміщення певного виду інформації. Зокрема, в сегменті коду програми зберігаються команди програми, в сегменті даних – значення глобальних змінних і типізованих констант.
Сегмент стека (за замовчуванням - 16Кб) служить для збереження викликів підпрограм (їх точок повернення), а також локальних змінних. Його особливістю є принцип обробки свого вмісту. У програмному стеці доступним завжди є тільки один елемент – вершина стеку. Елементи стеку обробляються за принципом LIFO (Last Input - First Output) - “останнім ввійшов - першим вийшов”.
Коли здійснюється виклик підпрограми, відповідна точка повернення у блок верхнього рівня запам’ятовується у стеці і зберігається там до завершення роботи цієї підпрограми. Там же розміщуються і її локальні змінні. Після завершення роботи підпрограми стек автоматично очищається, що призводить до знищення розміщених там даних.
Слід зазначити, що під глобальні дані пам'ять (у сегменті даних) виділяється на етапі компіляції і її розмір залишається незмінним протягом усього часу виконання програми.
Способи передачі параметрів
Класифікація способів передачі параметрів. Параметри підпрограми використовуються як інструмент для передачі в неї вихідних даних і повернення в основну програму (зовнішню підпрограму) отриманих результатів. Така передача у самому простому випадку може здійснюватися і за допомогою глобальних змінних зовнішнього блоку, що дозволяє говорити про підпрограми без параметрів. При цьому очевидно, що підпрограма - це нісенітниця, якщо вона взагалі не використовує в якості вихідних даних ніяких даних з викликаючої програми і не повертає їй (або не виводить) результатів обчислень.
Загалом, параметри підпрограм розрізняються:
за механізмом передачі -
передаються за значенням (value);
передаються за адресою або за посиланням (addr);
за способом взаємодії з підпрограмою -
є тільки вхідним параметром (in);
є тільки вихідним параметром (out);
є як вхідним, так і вихідним параметром (inout).
Тому теоретично можливі 6 способів передачі параметрів:
-
value in
value out
value inout
addr in
addr out
addr inout
Дамо коротку характеристику цихспособів передачі параметрів.Але спочатку узагальнимоосновні кроки процесувиклику підпрограми з фізичної точки зору, які є спільними для усіх шести способів. Зокрема, при виклику підпрограми:
в стеці виділяється пам'ять під процес виконання такого виклику;
обчислюється і запам'ятовується у стеці точка повернення в основну програму (підпрограму верхнього рівня);
за необхідності у стеці виділяється пам'ять під формальні параметри та локальні дані підпрограми (якщо вони є);
за необхідності вказаним способом готуються і передаються у підпрограму її аргументи;
виконуються оператори тіла підпрограми;
результат виклику підпрограми копіюється в пам'ять основної програми;
за адресою точки повернення в основну програму (підпрограму верхнього рівня), збереженою у п. 2, здійснюється повернення в основну програму (підпрограму верхнього рівня);
пам'ять, виділена під процес виконання виклику підпрограми (зокрема, під формальні параметри і локальні дані), очищається.
Після закінчення роботи підпрограми процес виконання основної програми продовжується із точки повернення в неї. Пам'ятьстека стає недоступноюпрограмі і можна вважати, що вонаочищена.Томуїї можна наново зайняти під локальні змінні при виконанні наступноговиклику якої-небудь підпрограми.
Особливості реалізації кожного із способів передачі параметрів наведено у табл. 1 (можутьмати місцевідмінності при конкретній реалізації в деякихмовахпрограмування).
Таблиця 1. Особливості реалізації передачі параметрів у підпрограми
Тип параметра |
При виклику підпрограми |
Під час роботи підпрограми |
По завершенні підпрограми |
value in |
виконується копіювання значень фактичних параметрів у стек |
зміна значень формальних параметрів не впливає на вміст комірок пам'яті фактичних параметрів |
нові значення формальних параметрів, отримані в процесі роботи підпрогра-ми, губляться разом з очищенням пам'яті |
value out |
|
|
використовуючи скопійовані адреси фактичних параметрів,виконується запис результуючих значень формальних параметрів у комірки пам'яті фактичних параметрів |
value inout |
|
|
використовуючи скопійовані адреси фактичних параметрів,виконується запис результуючих значень формальних параметрів у комірки пам'яті фактичних параметрів |
addr in |
виконується копіювання адрес (але не значень!) фактичних параметрів у стек |
|
вплив підпрограми на викликаючу через такі параметри відсутній |
addr out |
|
|
спеціального копіювання результатів не потрібно, оскільки результат відразу зберігається у комірках па-м'яті фактичних параметрів |
addr inout |
|
|
спеціального копіювання результату не потрібно, оскільки всі дії з формальними параметрами виконувалися безпосередньо над комірками пам'яті фактичних параметрів |
В мовах програмування, як правило, використовується не більше двох - трьох зазначених способів передачі параметрів. Зокрема, у мові Pascal реалізовані наступні три способи:
за значенням (value in);
за адресою з аргументами-покажчиками (addr inout);
за адресою з аргументами-константами (addr in).
У С/С++ підтримуються такі способи передачі параметрів у функції:
за значенням (value in);
за адресою з аргументами-покажчиками (addr inout);
за адресою з аргументами-посиланнями (addr inout).
Відповідно до способів передачі параметрів, що підтримуються мовами програмування, розрізняють параметри–значення, параметри–змінні, параметри–посилання, параметри– константи.
Параметри–значення. Це параметри, які передаються у підпрограму способом value in. Відповідні параметри називають параметрами-значеннями, оскільки кожен такий параметр в тілі підпрограми представляє значення відповідного фактичного параметра.
Даний спосіб передачі параметрів передбачає, що під час виклику підпрограми обчислюється значення відповідного аргументу (фактичного параметра) і копія отриманого результату передається підпрограмі (відповідному формальному параметру). Зміна параметрів-значень усередині підпрограми не впливає на значення змінних, які могли бути вказані як аргументи підпрограми, оскільки змінюються їх копії. Механізм передачі параметрів-значень можна представити наступною схемою:
Після ініціалізації формального параметра значенням фактичного параметра, останній є недоступним з підпрограми - вона не в змозі ні змінити його, ані використати яким-небудь іншим способом.
Декларування такого способу передачі параметрів, зазвичай, здійснюється шляхом задання ідентифікатора формального параметра. РБНФ для С/С++:
параметр-значення = тип ім'я.
Як фактичні параметри-значення можуть використовуватися константи, змінні, вирази.
Наприклад,
void func (int);
main ( )
{ int n = 4;
n= func(n);
cout << “n = “ << n << endl;
system(“pause“);
}
void func (int num)
{ return (num + 5) *num;
}
Тут формальний параметр num оголошується як звичайна локальна змінна, а фактичним параметром оператора виклику функції func є змінна n.
Параметри–змінні. Якщо передача параметрів відбувається за значеннями, то у тілі підпрограми не можна змінити значення змінних, що є фактичними параметрами. Однак, формальні параметри підпрограми можуть визначати не лише дані, які передаються на обробку до підпрограми, а також дані, які можуть повертатися підпрограмою у вигляді результатів. Такі параметри в тілі підпрограми повинні представлятися не значеннями, які є тільки вхідними даними підпрограми, а деякими змінними, що існують поза тілом підпрограми. Щоб підпрограма могла присвоїти значення таким змінним, необхідно забезпечити безпосередній доступ до них із підпрограми.
Такі можливості притаманні так званим параметрам-змінним – параметрам, які передаються у підпрограму способом addr inout. Механізм передачі параметрів такого типу можна представити наступним чином:
При виклику підпрограми формальному параметру-змінній передається не значення фактичного параметра, а адреса аргумента в сегменті даних оперативної пам’яті. Це дає змогу підпрограмі виконувати дії над значенням змінної, а не над її копією, тобто, напряму модифікувати значення змінної, що була вказана як аргумент в операторі виклику підпрограми.
На відміну від формального параметра-значення, фактичним параметром для якого може бути будь-який вираз відповідного типу, для параметра-змінної фактичним параметром може бути лише змінна (її адреса).
Якщо деякий параметр підпрограми представляє результат її виконання, то він обов'язково повинен задаватися як формальний параметр-змінна.
Щоб відрізнити формальний параметр-змінну від параметра-значення у мові Pascal, перед ним в списку параметрів записується службове слово var. УС/С++для реалізації даного способу передачі параметрів треба описати відповідний формальний параметр як покажчик натип аргумента функції, а в якості фактичного параметра в операторі виклику функції передатиадресуцього аргумента. У цьому випадку формальному параметру передається не значення, аадреса аргумента, що надає функції можливість прямого доступу до даних, які передаються, а також можливість зміни цих даних, використовуючи операцію розіменування.
Наприклад,
void prim (int *);
main ( )
{ int n = 4;
prim (&n);
cout << “n = “ << n << endl;
system(“pause“);
}
void prim (int *nPtr)
{ *nPtr = (*nPtr + 5) * *nPtr;
}
Недоліком даного споособу передачі параметрів є недостатня захищеність даних, оскільки підпрограма має доступ до них і можезіпсувати дані, що передаються до неї.
Параметри-посилання. Це різновид параметрів-змінних. Характерним такий спосіб передачі параметрів є для мовС/С++.
Якщо параметр оголошено як параметр-посилання, то підпрограмі передається адреса аргумента — змінної в сегменті даних оперативної пам’яті. Тому підпрограма виконує дії над значенням змінної, а не над її копією, і модифікація параметра-посилання приводить до модифікації змінної, що була вказана як аргумент в операторі виклику підпрограми. Тобто, при використанні параметра-посилання відбувається пряме звертання до аргумента функції, але через його псевдонім (інше ім’я).
Механізм передачі параметрів за посиланням можна представити так:
Для задання такого способу передачі параметрів у заголовку підпрограми треба відповідний формальний параметр описати як посилання на тип аргумента функції, а в якості фактичного параметра в операторі виклику функції вказати ідентифікатор змінної-аргумента.
Наприклад,
void prim (int &);
main ( )
{ int n = 4;
prim (n);
cout << “n = “ << n << endl;
system(“pause“);
}
void prim (int &nRef)
{ nRef *= nRef ;
}
Параметри-константи. Параметри-константи – це параметри, що передаються у підпрограму за адресою способом addr in. Такий спосіб передачі параметрів використовується коли значення, що передаються у функцію, не повинні змінюватися, навіть при виконанні дій над копією аргументу.
Механізм передачі параметрів-констант можна представити наступним чином:
Такий спосіб передачі параметрів використовується, наприклад, у мові Pascal, але для мов С/С++ він не передбачений.
Для декларації передачі параметрів підпрограм, як параметрів-констант, у Pascal слід при описі заголовків підпрограм перед ідентифікаторами параметрів-констант ставити ключове слово const. Наприклад,
Procedure Proc (const par1, par2 : byte; const par3 : word).
В якості фактичних параметрів-констант можуть використовуватися як змінні, так і константи. Однак, забороняється виконувати присвоювання формальним параметрам-константам і формальні параметри-константи не можуть передаватися як фактичні параметри іншим підпрограмам.
Параметри-константи доцільно використовувати у випадках, коли потрібно передавати структури даних, які займають великий об’єм пам'яті, але змінювати вихідні значення параметрів з алгоритмічної точки зору неприпустимо. У результаті економно використовується ОП і одночасно гарантується цілісність вихідних даних.
Якщо оперативної пам’яті недостатньо і термін виконання програми є важливим фактором, то слід використовувати параметри-покажчики. Якщо до терміну виконання програми та обсягу пам’яті, що його вона потребує, не висуваються жорсткі вимоги, то з метою захисту даних від випадкових змін слід передавати параметри як параметри-значення.
Слід зауважити, що не може бути повної незалежності між підпрограмами. Залежність між ними існує:
через списки параметрів;
тоді, коли вони користуються спільними (глобальними) змінними;
всі блоки програми залежать від структури даних цієї програми;
підпрограми залежать від логіки функціонування програми (від того фактору, що підпрограма може викликатися іншими підпрограмами).
Однак, бажано, щоб підпрограми були незалежними в межах інтерфейсу програми і структури даних. Практика показала, що чим вищий ступінь незалежності блоків, тим простіше розібратись в окремих підпрограмах і в програмі в цілому; тим менша ймовірність появи нових помилок при виправленні старих, або внесенні змін в програму, тобто менша ймовірність так званого хвильового ефекту.
Тому не слід без крайньої необхідності використовувати в підпрограмах глобальні змінні. Всі зв’язки між підпрограмами повинні підтримуватися через списки параметрів.