Покажчики дають великі можливості функціям "С", яким ми обмежуємось повернути одне значення. Завдяки параметрам покажчика наші функції тепер можуть обробляти фактичні дані, а не копіювати дані.
Для того, щоб змінити фактичні значення змінних, оператор, що викликає, передає адреси параметрам покажчика у функції.
У цьому підручнику ви дізнаєтесь-
- Приклади покажчиків на функції
- Функції з параметрами масиву
- Функції, що повертають масив
- Покажчики функцій
- Масив покажчиків на функції
- Функції, що використовують порожні вказівники
- Покажчики функцій як аргументи
Приклади покажчиків на функції
Наприклад, наступна програма міняє місцями два значення з двох:
void swap (int *a, int *b);int main() {int m = 25;int n = 100;printf("m is %d, n is %d\n", m, n);swap(&m, &n);printf("m is %d, n is %d\n", m, n);return 0;}void swap (int *a, int *b) {int temp;temp = *a;*a = *b;*b = temp;}}
Вихід:
m is 25, n is 100m is 100, n is 25
Програма міняє місцями фактичні значення змінних, оскільки функція отримує до них доступ за адресою за допомогою покажчиків. Тут ми обговоримо процес програми:
- Ми оголошуємо функцію, відповідальну за обмін двома значеннями змінних, яка приймає два цілочисельних покажчика як параметри і повертає будь-яке значення, коли воно викликане.
- У головній функції ми оголошуємо та ініціалізуємо дві цілочисельні змінні ('m' та 'n'), після чого друкуємо їх значення відповідно.
- Ми викликаємо функцію swap (), передаючи адресу двох змінних як аргументи, використовуючи символ амперсанда. Після цього ми друкуємо нові замінені значення змінних.
- Тут ми визначаємо вміст функції swap (), який приймає в якості параметрів дві цілочисельні адреси змінних, і оголошуємо тимчасову цілу змінну, яка використовується як третє поле зберігання, щоб зберегти одну зі змінних значень, яка буде додана до другої змінної.
- Збережіть вміст першої змінної, вказаної на 'a', у тимчасовій змінній.
- Зберігайте другу змінну, на яку вказує b, у першу змінну, на яку вказує a.
- Оновіть другу змінну (на яку вказує b) за значенням першої змінної, збереженої у тимчасовій змінній.
Функції з параметрами масиву
У C ми не можемо передавати масив за значенням функції. Тоді як ім’я масиву є покажчиком (адресою), тому ми просто передаємо ім’я масиву функції, що означає передачу вказівника на масив.
Наприклад, ми розглядаємо таку програму:
int add_array (int *a, int num_elements);int main() {int Tab[5] = {100, 220, 37, 16, 98};printf("Total summation is %d\n", add_array(Tab, 5));return 0;}int add_array (int *p, int size) {int total = 0;int k;for (k = 0; k < size; k++) {total += p[k]; /* it is equivalent to total +=*p ;p++; */}return (total);}
Вихід:
Total summation is 471
Тут ми пояснимо код програми та її деталі
- Ми оголошуємо та визначаємо функцію add_array (), яка приймає в якості параметрів адресу масиву (покажчик) із номером її елементів і повертає загальне накопичене підсумовування цих елементів. Вказівник використовується для ітерації елементів масиву (за допомогою позначення p [k]), і ми накопичуємо підсумовування в локальній змінній, яка повертається після ітерації всього масиву елементів.
- Ми оголошуємо та ініціалізуємо цілочисельний масив з п’ятьма цілочисельними елементами. Ми друкуємо загальне підсумовування, передаючи ім'я масиву (який діє як адреса) та розмір масиву в add_array (), що називається функцією як аргументи.
Функції, що повертають масив
У C ми можемо повернути покажчик на масив, як у наступній програмі:
#includeint * build_array();int main() {int *a;a = build_array(); /* get first 5 even numbers */for (k = 0; k < 5; k++)printf("%d\n", a[k]);return 0;}int * build_array() {static int Tab[5]={1,2,3,4,5};return (Tab);}
Вихід:
12345
І тут ми обговоримо деталі програми
- Ми визначаємо та оголошуємо функцію, яка повертає адресу масиву, що містить ціле значення, і не взяла жодних аргументів.
- Ми оголошуємо цілочисельний покажчик, який отримує повний масив, побудований після виклику функції, і друкуємо його вміст шляхом ітерації всього масиву з п'яти елементів.
Зверніть увагу, що вказівник, а не масив, визначений для зберігання адреси масиву, що повертається функцією. Також зауважте, що коли функція повертає локальну змінну, ми повинні оголосити її як статичну у функції.
Покажчики функцій
Як ми за визначенням знаємо, що вказівники вказують на адресу в будь-якому місці пам'яті, вони також можуть вказувати на початок виконуваного коду як функції в пам'яті.
Покажчик на функцію оголошується зі знаком *, загальний виклад його оголошення:
return_type (*function_name)(arguments)
Ви повинні пам’ятати, що дужки навколо (* ім'я_функції) важливі, оскільки без них компілятор буде думати, що ім'я функції повертає покажчик return_type.
Після визначення покажчика функції ми маємо призначити його функції. Наприклад, наступна програма оголошує звичайну функцію, визначає покажчик функції, призначає покажчик функції звичайній функції і після цього викликає функцію через покажчик:
#includevoid Hi_function (int times); /* function */int main() {void (*function_ptr)(int); /* function pointer Declaration */function_ptr = Hi_function; /* pointer assignment */function_ptr (3); /* function call */return 0;}void Hi_function (int times) {int k;for (k = 0; k < times; k++) printf("Hi\n");}
Вихід:
HiHiHi
- Ми визначаємо та оголошуємо стандартну функцію, яка друкує Hi-текст k разів, зазначених параметром times при виклику функції
- Ми визначаємо функцію покажчика (з її спеціальним оголошенням), яка приймає цілочисельний параметр і нічого не повертає.
- Ми ініціалізуємо нашу функцію вказівника за допомогою функції Hi_, що означає, що вказівник вказує на функцію Hi_function ().
- Замість стандартного виклику функції, пов'язуючи ім'я функції аргументами, ми викликаємо лише функцію покажчика, передаючи число 3 як аргументи, і все!
Майте на увазі, що ім’я функції вказує на початкову адресу виконуваного коду, як ім’я масиву, яке вказує на перший елемент. Отже, такі інструкції, як function_ptr = & Hi_function та (* funptr) (3), є правильними.
ПРИМІТКА: Не важливо вставляти оператор адреси & та оператор опосередкування * під час призначення функції та виклику функції.
Масив покажчиків на функції
Масив покажчиків на функції може грати перемикач або роль оператора if для прийняття рішення, як у наступній програмі:
#includeint sum(int num1, int num2);int sub(int num1, int num2);int mult(int num1, int num2);int div(int num1, int num2);int main(){ int x, y, choice, result;int (*ope[4])(int, int);ope[0] = sum;ope[1] = sub;ope[2] = mult;ope[3] = div;printf("Enter two integer numbers: ");scanf("%d%d", &x, &y);printf("Enter 0 to sum, 1 to subtract, 2 to multiply, or 3 to divide: ");scanf("%d", &choice);result = ope[choice](x, y);printf("%d", result);return 0;}int sum(int x, int y) {return(x + y);}int sub(int x, int y) {return(x - y);}int mult(int x, int y) {return(x * y);}int div(int x, int y) {if (y != 0) return (x / y); else return 0;}
Enter two integer numbers: 13 48Enter 0 to sum, 1 to subtract, 2 to multiply, or 3 to divide: 2624
Тут ми обговорюємо деталі програми:
- Ми оголошуємо та визначаємо чотири функції, які приймають два цілочисельні аргументи і повертають ціле значення. Ці функції додають, віднімають, множать і ділять два аргументи щодо того, яку функцію викликає користувач.
- Ми оголошуємо 4 цілих числа для обробки операндів, типу операції та результату відповідно. Крім того, ми оголошуємо масив із чотирьох покажчиків на функції. Кожен покажчик функції елемента масиву приймає два цілі параметри і повертає ціле значення.
- Ми призначаємо та ініціалізуємо кожен елемент масиву за допомогою вже оголошеної функції. Наприклад, третій елемент, який є вказівником третьої функції, вказуватиме на функцію операції множення.
- Ми шукаємо операнди та тип операції у користувача, набраного за допомогою клавіатури.
- Ми викликали відповідний елемент масиву (покажчик функції) з аргументами, і ми зберігаємо результат, згенерований відповідною функцією.
Інструкція int (* ope [4]) (int, int); визначає масив покажчиків на функції. Кожен елемент масиву повинен мати однакові параметри та тип повернення.
Результат твердження = ope [вибір] (x, y); запускає відповідну функцію відповідно до вибору, зробленого користувачем. Два введені цілі числа є аргументами, переданими функції.
Функції, що використовують порожні вказівники
Покажчики порожнечі використовуються під час оголошень функцій. Ми використовуємо дозволи на повернення void * для повернення будь-якого типу. Якщо ми вважаємо, що наші параметри не змінюються при передачі функції, ми оголошуємо це як const.
Наприклад:
void * cube (const void *);
Розглянемо таку програму:
#includevoid* cube (const void* num);int main() {int x, cube_int;x = 4;cube_int = cube (&x);printf("%d cubed is %d\n", x, cube_int);return 0;}void* cube (const void *num) {int result;result = (*(int *)num) * (*(int *)num) * (*(int *)num);return result;}
Результат:
4 cubed is 64
Тут ми обговоримо деталі програми:
- Ми визначаємо та оголошуємо функцію, яка повертає ціле значення і приймає адресу незмінної змінної без певного типу даних. Ми обчислюємо значення куба змінної змісту (x), на яку вказує вказівник num, і оскільки це порожній вказівник, ми повинні ввести його, приводячи його до цілочисельного типу даних, використовуючи конкретний нотатор (* тип даних), і повертаємо значення куба.
- Ми оголошуємо операнд і змінну результату. Крім того, ми ініціалізуємо наш операнд зі значенням "4."
- Ми викликаємо функцію куба, передаючи адресу операнда, і обробляємо значення, що повертається, у змінну результату
Покажчики функцій як аргументи
Інший спосіб використовувати покажчик функції, передаючи його як аргумент іншій функції, яку іноді називають "функцією зворотного виклику", оскільки отримуюча функція "викликає її назад".
У файлі заголовка stdlib.h функція Quicksort "qsort ()" використовує цю техніку, яка є алгоритмом, призначеним для сортування масиву.
void qsort(void *base, size_t num, size_t width, int (*compare)(const void *, const void *))
- void * base: порожній вказівник на масив.
- size_t num: Номер елемента масиву.
- size_t width Розмір елемента.
- int (* порівняти (const void *, const void *): покажчик функції, що складається з двох аргументів і повертає 0, коли аргументи мають однакове значення, <0, коли arg1 стоїть перед arg2, і> 0, коли arg1 постає після arg2.
Наступна програма сортує цілочисельний масив від малого до великого числа за допомогою функції qsort ():
#include#include int compare (const void *, const void *);int main() {int arr[5] = {52, 14, 50, 48, 13};int num, width, i;num = sizeof(arr)/sizeof(arr[0]);width = sizeof(arr[0]);qsort((void *)arr, num, width, compare);for (i = 0; i < 5; i++)printf("%d ", arr[ i ]);return 0;}int compare (const void *elem1, const void *elem2) {if ((*(int *)elem1) == (*(int *)elem2)) return 0;else if ((*(int *)elem1) < (*(int *)elem2)) return -1;else return 1;}
Результат:
13 14 48 50 52
Тут ми обговоримо деталі програми:
- Ми визначаємо функцію порівняння, що складається з двох аргументів, і повертає 0, коли аргументи мають одне і те ж значення, <0, коли arg1 стоїть перед arg2, і> 0, коли arg1 постає після arg2. (ціле число)
- Ми визначаємо та ініціалізуємо цілочисельний масив Розмір масиву зберігається у змінній num, а розмір кожного елемента масиву зберігається у змінній ширини, використовуючи заздалегідь визначений оператор C.
- Ми викликаємо функцію qsort і передаємо ім'я масиву, розмір, ширину та функцію порівняння, визначені раніше користувачем, щоб відсортувати наш масив за зростанням. Порівняння буде виконано шляхом взяття в кожній ітерації двох елементів масиву, поки весь масив буде відсортовано.
- Ми друкуємо елементи масиву, щоб переконатися, що наш масив добре відсортований, перебираючи весь масив, використовуючи цикл for.