Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Книга6.doc
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
2.45 Mб
Скачать

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

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

У програмі на мові С адресою функції служить її ім'я без дужок і аргументів (це схоже на адресу масиву, який дорівнює імені масиву без індексів). Розглянемо наступну програму, в якій порівнюються два рядки, введені користувачем. Зверніть увагу на оголошення функції check () і покажчик p всередині main (). Покажчик p є покажчиком на функцію.

Приклад 6.16. Порівняння стрічок з використанням покажчиків на функцію.

# include <stdio.h>

# include <string.h>

void check (char *a, char * b,

int (*cmp) (const char *, const char *));

int main (void)

{

char s1 [80], s2 [80];

int (* p) (const char *, const char *);

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

p = strcm /* Привласнює адресу функції strcmp

вказівником p* */

printf ("Enter two strings.\ n");

gets (s1);

gets (s2);

check (s1, s2, p); /* Передає адресу функції strcmp

за допомогою покажчика p */

return 0;

}

void check (char * a, char * b,

int (* cmp) (const char *, const char *))

{

printf ("Check for overlap \ n");

if (! (* cmp) (a, b)) printf ("The same. ");

else printf ("Not the same. ");

}

Проаналізуємо цю програму докладно. У першу чергу розглянемо оголошення покажчика p в main ():

int (* p) (const char *, const char *);

Це оголошення повідомляє компілятору, що p – це покажчик на функцію, що має два параметри типу const char * і повертає значення типу int. Дужки навколо p необхідні для правильної інтерпретації оголошення компілятором. Подібна форма оголошення використовується також для покажчиків на будь-які інші функції, потрібно лише внести зміни в залежності від типу, що повертається і параметрів функції.

Тепер розглянемо функцію check ().У ній оголошені три параметри: два покажчика на символьний тип (a і b) і покажчик на функцію cmp. Зверніть увагу на те, що покажчик функціїcmp оголошено в тому ж форматі, що і p. Тому в cmp можна зберігати значення покажчика на функцію, що має два параметри типу const  char * і повертає значення int. Як і в оголошенні p, круглі дужки навколо  *cmp  необхідні для правильної інтерпретації цього оголошення компілятором.

Спочатку в програмі покажчиком  p присвоюється адресу стандартної бібліотечної функції strcmp (), яка порівнює рядки. Потім програма просить користувача ввести два рядки і передає покажчики на них функції check (), яка їх порівнює. Усередині check () вираз (*Cmp) (a, b) викликає функцію  strcmp (), на яку вказує cmp, з аргументами a і b. Дужки навколо *cmp обов'язкові. Існує й інший, більш простий, спосіб виклику функції за допомогою покажчика:

cmp (a, b);

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

Виклик функції  check () можна записати, використовуючи безпосередньо ім'я strcmp ():

check (s1, s2, strcmp);

В цьому випадку вводити в програму додатковий покажчик p немає необхідності.

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

Альтернативний підхід – використання оператора switch з довгим списком міток case – робить програму більш громіздкою і схильною до помилок.

У наступному прикладі розглядається розширена версія попередньої програми. У цій версії функція check () влаштована так, що може виконувати різні операції над рядками s1 і s2 (наприклад, порівнювати кожен символ з відповідним символом іншого рядка або порівнювати числа, записані в рядках) залежно від того, яка функція вказана в списку аргументів .Наприклад, рядки "0123" і "123" відрізняються, проте представляють один і той же числове значення.

Приклад 6.17. Детальна версія попередньої програми (функція check () влаштована так, що може виконувати різні операції над рядками s1 і s2)

#include <stdio.h>

#include <ctype.h>

#include <stdlib.h>

#include <string.h>

void check (char*a, char*b,

int (*cmp)(const char*, const char*));

int compvalues(const char *a, const char*b);

int main(void)

{

char s1[80], s2[80];

printf("Enter two strings.\n");

gets(s1);

gets(s2);

if (isdigit(*s1)) {

printf(".\n");

check(s1, s2, compvalues);

}

else {

printf("Check for overlap.\n");

check(s1, s2, strcmp);

}

return 0;

}

void check(char*a, char*b,

int (*cmp)(const char*, const char*))

{

if(!(*cmp)(a, b)) printf("The same ");

else printf("Not the same ");

}

int compvalues(const char *a, const char *b)

{

if(atoi(a)==atoi(b)) return 0;

else return 1;

}

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

Якщо в цьому прикладі ввести перший символ першого рядка як цифру, то check () використовує compvalues (), в іншому випадку – strcmp (). Функція check () викликає ту функцію, ім'я якої зазначено в списку аргументів при виклику check (), тому вона в різних ситуаціях може викликати різні функції. 

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]