Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Архив WinRAR / 2_Посібник_С_002.doc
Скачиваний:
39
Добавлен:
17.05.2015
Размер:
2.7 Mб
Скачать

5.9 Посилання в якості результатів функції

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

Приклад 19. Синтаксис.

double & rf (int p);

необхідний аргумент цілого типу, і вона повертає посилання на об'єкт double, ймовірно оголошеного десь в іншому місці.

Функція знаходить та повертає посилання на найбільший елемент масиву:

Приклад 20. Пошук посилання на найбільший елемент масиву.

int &max(int n, int d[]){

int a=0;

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

a = d[a]>d[i]?a:i; /*якщо елемент з індексом im більший чим елемент з індексом і то im присвоюється im (тобто без змін), а якщо твердження не правильне то im присвоюється значення і*/

return d[a];

}

int main (){

int x[]={10, 20, 30, 15};

int n=4;

printf("max(n,x) = %i \n", max(n,x));

max(n,x) = 0;

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

printf("x[%i]= %i\n",i, x[i]);

system("PAUSE");

return EXIT_SUCCESS;

}

Результат роботи програми:

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

5.10 Покажчики на функцію

Перш ніж вводити покажчик на функцію, нагадаємо, що кожна функція характеризується типом значення, що повертається, ім'ям та сигнатурою. Нагадаємо, що сигнатура визначається кількістю, порядком проходження і типами параметрів. Іноді кажуть, що сигнатурою функції називається список типів її параметрів.

А тепер шляхом послідовності тверджень прийдемо до обговорення теми:

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

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

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

4. Покажчик на функцію визначається таким чином:

Приклад 21. Синтаксис.

Тип_функціі (* імя_покажчика) (специфікація_параметрів);

Наприклад: int (* func1Ptr) (char);- визначення покажчика func1Ptr на функцію з параметром типу char, що повертає значення типу int.

Примітка: Будьте уважні! Якщо наведену синтаксичну конструкцію записати без перших круглих дужок, тобто у вигляді int * fun (char); то компілятор сприйме її як прототип якоїсь функції з ім'ям fun і параметром типу char, що повертає значення покажчика типу int *.

Другий приклад: char * (* func2Ptr) (char *, int); - визначення покажчика func2Ptr на функцію з параметрами типу покажчик на char і типу int, яка повертає значення типу покажчик на char.

Представлення на практиці.

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

Приклад 22. Покажчик на функцію.

void Fone (void) /* Визначення Fone.*/

{

printf("Load Fone() \ n");

}

void Ftwo (void) /* Визначення Ftwo.*/

{

printf("Load Ftwo () \ n");

}

int main (){

void (* ptof) (void); /* ptof - покажчик на функцію.*/

ptof = Ftwo; /* Присвоюється адресу Ftwo ()*/

(*ptof) (); /* Виклик Ftwo () за її адресою.*/

ptof = Fone; /* Присвоюється адресу Fone ()*/

(*ptof) (); /* Виклик Fone () за її адресою.*/

ptof (); /* Виклик еквівалентний (*ptof) ();*/

}

Результат робти::

Тут значенням імені_покажчика служить адреса функції, а за допомогою операції розіменовування * забезпечується звернення за адресою до цієї функції. Проте буде помилкою записати виклик функції без дужок у вигляді * ptof ();. Справа в тому, що операція () має більш високий пріоритет, ніж операція звернення за адресою *. Отже, відповідно до синтаксисом буде спочатку зроблена спроба звернутися до функції ptof (). І вже до результату буде віднесена операція розіменовування, що буде сприйнято як синтаксична помилка.

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

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

Приклад 23. Недопустимі оператори.

char cfc (char) {...} /* Визначення функції.*/

char cfi (int) {...} /* Визначення функції.*/

void vff (float) {...} /* Визначення функції.*/

int * ifc (char *){...} /* Визначення функції.*/

char (* ptof1) (int); /* Покажчик на функцію.*/

char (* ptof2) (int); /* Покажчик на функцію.*/

void (* ptof3) (float) = vff; /*ініціалізувати покажчик.*/

int main ()

{

ptof1 = cfc; /* Помилка - невідповідність сигнатур.*/

ptof2 = vff; /* Помилка - невідповідність типів (значень і сигнатур).*/

ptof1 = ifc; /* Помилка - невідповідність типів.*/

ptof1 = cfi; /* Правильно.*/

ptof2 = pt1; /* Правильно.*/

char c = (* ptof1) (44); /* Правильно.*/

c = (* ptof2) ('\ t'); /* Правильно.*/

}

Приклад 24. Відображення гнучкості механізму викликів функцій за допомогою покажчиків.

/* Функції одного типу з однаковими сигнатурами:*/

#include <stdio.h>

#include <stdlib.h>

int plus (int a, int b) {return a + b;}

int divide(int a, int b) {return a / b;}

int multiple (int a, int b) {return a * b;}

int subtruct (int a, int b) {return a - b;}

int main (){

int (* ptof) (int, int); /*оголошення вказ³вника

int var1 = 12, var2 = 4;

char c = '+';

while (c != '\040'){

printf("\nArguments: var1 =%i, var2 =%i", var1, var2);

printf(". Result for c = \'%i\', ", c);

switch (c){

case '+':

ptof = plus;

c = '/';

break;

case '-':

ptof = subtruct;

c = ' ';

break;

case '*':

ptof = multiple;

c = '-';

break;

case '/':

ptof = divide;

c = '*';

break;

}

var1 = (* ptof) (var1, var2 );

printf("var1 = (* ptof) (var1, var2)\n", var1);

}

system("PAUSE");

return EXIT_SUCCESS;

}

Результати роботи:

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

Найкраще відобразити суть застосування можна на прикладі передачі функції в функцію (це рідко використовується):

Приклад 25. Передача функції в функцію(рис. 5.11)

int add(int a, int b){ return (a+b); }

int subtraction (int a, int b){ return (a-b); }

int operation (int x, int y, int (*functocall)(int,int))

{

int g;

g = (*functocall)(x,y);

return (g);

}

int main ()

{

int m,n;

int (*minus)(int,int) = subtraction; /*оголошення та ініціалізація покажчика на ф-ю subtraction*/

m = operation (7, 5, addition);

n = operation (20, m, minus);

printf("n= %i, m= %i \n", n, m);}

Виконання:

Змінній m присвоюється значення функції operation в яку передаються три параметри: 7,5 і адреса на функцію addition. В функції operation ми присвоюємо значення виконання функції покажчик і параметрами , якими їй передали при виклику з головної програми:

Рисунок 5.11 – Зображення прикладу 25.

Результат роботи програми:

Соседние файлы в папке Архив WinRAR