Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
КТіП Лекції 20110516 (1).doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
1 Мб
Скачать
☆
    1. Виклик функцій. Прототипи функцій

Оператори тіла функції виконується тільки тоді, коли здійснюється звертання до даної функції – виклик функції. Виклик функції позначається операцією «круглі дужки»:

ім’я_функції ( список_фактичних_параметрів )

список фактичних параметрів – це послідовність виразів, кожен з яких задає значення відповідного формального параметра, вказаного в описі даної функції. Фактичні і формальні параметри обов’язково мають бути узгодженими за кількістю, порядком розташування і типами.

Виклик функції, в оголошенні якої вказано тип void, є окремим оператором програми – наприклад, це виклик функції PrintSqrt( 4 ); – не входить до складу будь-якого виразу, закінчується крапкою з комою. Як окремий оператор можна організовувати і виклик функцій, які повертають значення – воно буде проігноровано.

Якщо функція повертає значення, воно передається в те місце програми, з якого викликали дану функцію. Значення, повернене функцією, можна використовувати у всіх виразах як звичайний операнд, тип якого збігається з типом значення функції.

Компілятор контролює правильність звертання до функції та застосування значення, яке вона повертає, тому опис функції повинен передувати звертанню до неї. Довільний порядок запису функцій забезпечується використанням прототипів функцій. Прототип функції повторює рядок її заголовку і закінчується знаком крапка з комою:

тип_значення_функції ім’я_функції ( оголошення_параметрів );

Прототипи функцій необхідно вказувати перед першим звертанням до функції. Часто прототипи функцій записують на початку програми, а повні описи функцій розміщують пізніше. У списку параметрів прототипу функції можна вказувати тільки типи параметрів, опускаючи їх імена. Дозволено також вказувати в прототипі імена параметрів, відмінні від тих, що використані в описі функцій.

Використаємо прототипи функції в програмі:

#include <iostream>

using namespace std;

int sum( int a, int b ); // Прототип функції sum

int max( int a, int b ); // Прототип функції max

int main() {

int x = 3, y = 4;

cout << sum( x, y ) << endl;

cout << max( 2, x ) << endl;

}

int sum( int a, int b ) {

int t;

t = a + b;

return t;

}

int max( int a, int b ) {

if ( a > b )

return a;

return b;

}

    1. Взаємодія фактичних і формальних параметрів функцій

Коли відбувається звертання до функції, всі її формальні параметри отримують значення відповідних фактичних параметрів, заданих у виклику цієї функції. Тому кількість фактичних параметрів повинна строго відповідати кількості формальних параметрів. Фактичні параметри можуть бути довільними виразами, але тип значення кожного з них має бути сумісним з типом відповідного формального параметра, тобто значення виразу може бути перетворене до типу формального параметру.

Механізм взаємодії формальних і фактичних параметрів при виклику і виконанні функції такий:

  1. послідовно обчислюються значення виразів, записаних у виклику функції, тобто значення її фактичних параметрів;

  2. значення кожного з фактичних параметрів перетворюється до типу відповідного формального параметру, перетворення виконується згідно з правилами узгодження типів в операціях присвоєння;

  3. для кожного формального параметру функції створюється змінна, якій присвоюється значення відповідного фактичного параметру;

  4. ці змінні використовуються всередині функції при її роботі;

  5. після завершення роботи функції пам’ять, яку було виділено для параметрів і внутрішніх змінних функції, звільняється.

Таким чином, в тілі функції опрацьовуються копії значень фактичних параметрів, значення самих фактичних параметрів при цьому не змінюються. Це важливий момент, який обов’язково необхідно враховувати при створенні функцій. Наступна функція повертає найбільше з трьох цілих чисел:

#include <iostream>

using namespace std;

int max( int a, int b, int c ) { // Формальні параметри

a = a > b ? a : b;

return a > c ? a : c;

}

int main() {

int x = 3, m;

m = max( х, 2, x + 1 ); // Фактичні параметри

cout << m << endl;

}

Формальні параметри в цьому прикладі – це змінні a, b, c, фактичні параметри – це значення 2, х, х+1. При звертанні до функції змінна а отримає значення змінної х, змінна b – значення 2, змінна c – значення виразу х+1. Всередині функції значення змінної а змінюється, але це не вплине на значення відповідного фактичного параметра, тобто х. Такий взаємозв’язок параметрів називається звертанням за значенням (call by value).

Зразком неправильного звертання за значенням параметрів може бути наступна функція, яка має міняти місцями значення двох змінних:

#include <iostream>

using namespace std;

void swap( int a, int b ) {

int t = a;

a = b;

b = t;

}

int main() {

int x = 3, y = 4;

swap( x, y );

cout << "x = " << x << endl;

cout << "y = " << y << endl;

}

Всередині функції значеннями будуть обмінюватися формальні параметри (a i b), які існують в пам'яті тільки під час існування функції. Значення фактичних параметрів, тобто значення змінних х і у, не змінюються.

Для того, щоб функція могла змінити значення змінної, треба передати в функцію адресу змінної. Тоді з функції можна буде звертатись безпосередньо до значення змінної. Відповідний фактичний параметр функції має бути вказівником, базовий тип якого збігається з типом змінної. Таку організацію взаємозв’язку параметрів, коли у функцію передаються адреси змінних, називають звертанням через посилання (call by reference).

Для того, щоб функція swap почала правильно працювати, необхідно передавати в цю функцію адреси змінних, тобто формальні параметри функцій мають бути вказівниками на змінні, значення яких переставляються:

void swap( int * a, int * b ) {

int t = *a;

*a = *b;

*b = t;

}

Створимо програму, яка буде переставляти елементи масиву в зворотному порядку. Функції для роботи з масивами запишемо в окремому заголовному файлі.

// array.h --------------------------------------------------------

#ifndef ARRAY_H

#define ARRAY_H

#include <iostream>

#include <ctime>

using namespace std;

//-----------------------------------------------------------------

void array_fill( int * p, int n ) {

srand( unsigned( time ( NULL ) ) );

for ( int i = 0; i < n; i++ )

p[ i ] = rand( ) % 100;

} //---------------------------------------------------------------

void array_print( int * p, int n ) {

for ( int i = 0; i < n; i++ )

cout << p[ i ] << "\t";

cout << endl;

} //---------------------------------------------------------------

void array_swap( int * a, int * b ) {

int t = *a;

*a = *b;

*b = t;

} //---------------------------------------------------------------

void array_reverse( int * p, int n ) {

for ( int i = 0; i < n / 2; i++ )

array_swap( &p[ i ], &p[ n - 1 - i ] );

}

#endif

#include "array.h"

#include <iostream>

using namespace std;

int main() {

const int NUM = 5;

int a[ NUM ];

array_fill( a, NUM );

array_print( a, NUM );

array_reverse( a, NUM );

array_print( a, NUM );

}

Функція main містить тільки оголошення констант, змінних і виклики функцій. Описи функцій зберігаються в файлі array.h, який можна підключати до будь-якого проекту.