- •2. Основні елементи мови с
- •3.1 Алфавіт мови програмування
- •3.2Лексеми
- •3.3Ключові слова
- •3.4Ідентифікатори
- •3.5 Класифікація типів даних
- •3.6 Літерали
- •3.7 Оператори
- •3.8 Коментарі
- •3.9 Директиви препроцесора
- •3.10 Організація програми
- •3. Операції та вирази
- •4.1 Загальні відомості
- •4.2 Арифметичні операції
- •4.3 Операції приведення типів
- •(Тип) ідентифікатор,
- •4.4 Операції присвоєння
- •4.5 Операції інкремента і декремента
- •4.6 Операції порівняння
- •4.7 Операції зсуву
- •4.8 Порозрядні операції
- •4.9 Логічні операції
- •4.10 Операція sizeof
- •Sizeof ( Вираз ),
- •4.11 Операція послідовного обчислення
- •4.12 Операція умови (?:)
- •Операнд-1 ? Операнд-2 : Операнд-3
- •4.13 Адресні операції
- •Тип * ім'я_покажчика;
- •4. Прості типи даних
- •5.1 Оголошення змінних
- •[ Модифікатори ] тип ім’я_змінної;
- •5.2 Час існування та область видимості змінних
- •5.3 Цілі типи даних
- •5.4 Дійсні типи даних
- •5. Оператори керування
- •5.1 Оператор розгалуження if
- •If ( Вираз ) true-оператор;
- •5.2 Оператор розгалуження if-else
- •If ( Вираз ) true-оператор; else false-оператор;
- •5.3 Оператор множинного розгалуження switch
- •5.4 Оператор циклу for
- •For ( Вираз 1 ; Вираз 2 ; Вираз 3 ) тіло циклу
- •5.5 Оператор циклу while
- •While ( Вираз ) тіло циклу
- •5.6 Оператор циклу do while
- •Тіло циклу while ( Вираз ) ;
- •5.7 Оператор break
- •5.8 Оператор continue
- •6 Введення та виведення даних
- •7.1 Функція виведення printf
- •Int printf( стрічка форматування, змінна1, змінна2, ... );
- •7.2Функція введення scanf
- •Int scanf (стрічка форматування, адреса змінної1, адреса змінної2, ... );
- •9.1 Введення та виведення у файл
- •7 Масиви
- •7.1 Загальні поняття
- •7.2 Одновимірні масиви
- •Тип даних ім’я змінної [n];
- •7.3 Багатовимірні масиви
- •6. Функції
- •6.1 Основні поняття
- •{Тіло функції}
- •6.2 Область видимості
- •6.3 Порожній тип void
- •6.4 Передача аргументів у функцію
- •6.5 Рекурсивні функції
- •6.6 Прототипи функцій
- •8. Рядки в с
- •4.1 Прототипи
- •4.2 Функції перетворення буферів
- •4.3 Функції перевірки літер
- •4.4 Рядок символів
- •4.5 Операції з рядками:
- •4.6 Символьні константи
- •9. Покажчики
- •5.1 Визначення та ініціалізація покажчиків
- •5.2 Визначення покажчиків:
- •5.3 Масиви
- •5.6 Копіювання рядка
- •5.7 Посилання та оператор &
- •5.9 Посилання в якості результатів функції
- •5.10 Покажчики на функцію
- •Тип_функціі (* імя_покажчика) (специфікація_параметрів);
- •5.11 Покажчики на void
- •5.12 Арифметика покажчиків
- •10. Структури, об’єднання, перерахування
- •7.1 Структури
- •7.2 Ключове слово typedef
- •7.3 Об’єднання
- •7.4Перераховуваний тип (Enum)
- •Enum dataType
- •Enum day
- •11 Динамічне виділення пам'яті
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.
Результат роботи програми: