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


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

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



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

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

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, який можна підключати до будь-якого проекту.

Inline – функції

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

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

 

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

int t = *a;

*a = *b;

*b = t;

}

 

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

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

 

inline int sqr(int x) {

return x * x;

}

 

Якщо звернутися до цієї функції для обчислення виразу

 

sqr(a + b) / (sqr(a) + sqr(b))

 

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

 

(a + b) * (a + b) / (a * a + b * b)

 



Поделиться:


Последнее изменение этой страницы: 2021-12-15; просмотров: 47; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.21.103.209 (0.009 с.)