Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

M_CI_5

.pdf
Скачиваний:
8
Добавлен:
12.05.2015
Размер:
698.33 Кб
Скачать

Лабораторна робота № 5.

(6 годин)

Функції.

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

5. Теоретичнi вiдомостi.

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

Для чого потрібні функції? По перше вони позбавляють вас повторного програмування. Якщо в програмі потрібно кілька раз виконати деяку задачу, то відповідну функцію можна написати тільки один раз і викликати її для виконання стільки раз, скільки це потрібно. Її можна використовувати в інших програмах у вигляді вихідного тексту, .OBJ файлу, або .LIB файлу (бібліотеки), як це ми робимо з функціями cos(), sin(), tan() і т. ін. По-друге, якщо задачу потрібно виконати і один раз, функції надають програмі модульну структуру і, таким чином, полегшують читання коду і внесення в нього виправлень та змін. І взагалі філософія розробки програм на Сі полягає у використанні функцій в якості будівельних блоків.

Нагадуємо, що структура функції, така ж, як і у головної функції main() (дивіться розділ

1).

5.1. Оголошення функцій. Функції, які нічого не повертають.

Розглянемо таку демонстраційну програму:

Приклад 5.1

 

 

 

 

 

 

1:

#include <stdio.h>

15:

int i;

2:

 

 

 

16:

printf("\n Рахунок від 1 до 10\n");

3:void Count_Up(void); 17: for (i = 1; i <= 10; i ++)

4:void Count_Down(void); 18: printf ("%4d", i);

5:

main()

19: }

6:

20:

7:

{

21: void Count_Down(void);

8:

Count_Up();

22: {

9:

Count_Down();

23: int i;

10: return 0;

24: printf("\n Рахунок від 10 до 1\n");

11: }

25: for (i = 10; i >= 1; i --)

12:

 

26: printf ("%4d", i);

13: void Count_Up(void);

27: }

14: {

28:

В рядках 3 і 4 оголошуються функції Count_Up(); Count_Down(). Ключове слово void перед іменами функцій використовується для того, оголосити, що ці функції не повертають ніяких значень. А це ж слово в круглих дужках (там де повинен бути список типів параметрів або аргументів) означає, що функції не передають аргументів і не мають параметрів.

Відповідно в тілах цих функцій немає оператора return.

Попередження!

66

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

Оголошення функцій в рядках 3 і 4 по-іншому називається прототипом функцій, а рядки 13 і 22 є заголовками або визначеннями функцій, а рядки з 14 по 20 та з 23 до 29 є тілами функцій.

Прототип і заголовок повинні співпадати в точності. Будь-які розходження між прототипом і заголовком (визначенням) можуть викликати помилки, які потім важко виявити, але яких можна уникнути, якщо правильно використовувати прототипи функцій.

На рис. 5.1 показана послідовність виконання програми, код якої приведено вище.

При кожному виклику функції, адреса поточної команди програми "проштовхується" в стек (LIFO). Адреса повернення, яка поміщена в стек, дозволяє функціям повертати управління туди, звідки вони були викликані.

Локальні змінні (такі, як і - дивіться приклад 5.1) також запам`ятовуються в стеці. Функцію можуть викликати будь-які оператори, також і ті які знаходяться всередині інших функцій.

Щоб вийти із функції в потрібний момент, потрібно виконати оператор return. Наприклад: void ім`я_функції (void)

 

 

 

 

 

 

 

{

 

 

 

 

 

 

 

 

 

 

if (умова)

 

 

 

 

main()

 

 

 

 

 

 

 

 

 

 

 

 

 

return;

 

 

 

 

 

 

 

void Count_Up();

 

блок_операторів

 

 

 

 

 

 

{

 

 

 

Count_Up();

 

 

}

 

 

 

 

 

 

 

 

 

 

 

 

 

}

 

5.2. Функції, які повертають

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

значення.

 

 

 

 

 

 

void

 

 

 

Count_Down();

 

 

 

 

 

Count_Down();

 

Для того, щоб функцію можна було б

 

 

 

 

 

 

 

 

 

 

 

 

 

{

 

 

 

 

 

 

 

використовувати

у

виразах, необхідно

 

 

 

 

 

 

 

 

 

return 0;

 

 

 

 

щоб, вона повертала значення того типу,

 

 

 

 

 

}

 

 

 

 

 

 

 

якого від неї чекають. Для цього потрібно

 

 

Рис. 5.1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

розмістити в тілі функції хоча б один

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

оператор return

в

потрібному місці

(дивіться рядки 20, 32 в обох програмах прикладу 6.2, та рядки 40, 43, 47 в програмі “Tak_Hi.C”. Крім того потрібно описати тип значення, яке повертає функція.

Приклад 5.2

 

 

 

 

 

 

 

 

 

“Yes No.C”

 

 

“Tak Hi.C”

1:

#include <stdio.h>

1:

#include <stdio.h>

2:

#include <ctype.h>

2:

/*#include <ctype.h>*/

3:

#define FALSE 0

3:

#define FALSE 0

4:

#define TRUE 1

4:

#define TRUE 1

5:

 

 

 

5:

 

 

6:

int User Quits(void);

6:

int User

Quits(void);

7:

void present(void);

7:

char in

upper(char);

8:

 

 

 

8:

 

 

9:

void main()

9:

void main()

10:

{

 

 

10:

{

 

11:

int i = 0;

11:

int i = 0;

12:

int quitting = FALSE;

12:

int quitting = FALSE;

13:

printf("Приклад виходу\n");

13:

printf("Пример выхода: \n");

14:

while (!quitting)

14:

while (!quitting)

15:

{

 

 

15:

{

 

16:

i ++;

16:

i ++;

 

17:

printf("i == %d\n",i);

17:

printf("i == %d\n",i);

67

18: quitting = User Quits();

18: quitting = User Quits();

19: }

 

19: }

20: return 0;

20: return 0;

21: }

 

21: }

22:

 

22:

23: int User Quits(void)

23: int User Quits(void)

24: {

 

24: {

25:

 

25:

26:

int c;

26: char c;

27:printf("Інше значення? 27: printf("Еще значение ?: \"Д\" =>Да \"Н\" =>Нет\n");

28:

do {

28:

do {

29:

c = getchar();

29:

c = getchar();

30:if(c!='\n') c = toupper(c) 30: if(c!='\n') c = in upper(c);

31:}while ((c != 'Y') && (c != 'N')); 31: }while ((c != 'Д') && (c != 'Н'));

32:

return (c == 'N');

32: return (c == 'Н');

33: }

 

33: }

 

34:

 

34: char in

upper(char c)

35:

 

35: {

 

36:

 

36: if(((c >= 'a') && (c <= 'z'))||((c >= 'а') && (c <= 'п')))

37:

 

37:

{ c = c - 32; return c; }

38:

 

38: else if (((c >= 'р') && (c <= 'я')))

39:

 

39:

{ c = c - 80; return c; }

40:

 

40: else if(((c >= 'A') && (c <= 'Z'))||((c >= 'А') && (c <= 'Я')))

41:

 

41:

return c;

42:

 

42: else

 

43:

 

43:

{

44:

 

44:

printf ("Це не літера!!! \n");

45:

 

45:

return -1;

46:

 

46:

}

47:

 

47: }

 

Приклад роботи програми “Tak_Hi.C”:

Пример выхода: i == 1

Еще значение ?: "Д" =>Да "Н" =>Нет

д

i == 2 7

Это не буква!!!

д

i == 4

Еще значение ?: "Д" =>Да "Н" =>Нет

н

(Програма “Yes_No.C” працює аналогічно, за виключенням того, що вона не працює з буквами кирилиці. Це тому, що в ній використовується бібліотечна функція toupper(c) (рядок 30), яка не працює з другою половиною таблиці ASCII. Програма “Tak_Hi.C” працює з кирилицею тому, що в ній використовується своя функція in_upper() переведення літер англійського та російського алфавіту в верхній регістр)

Попередження!

Оператор return обов`язково повинен бути, інакше функція поверне випадково

вибране значення.

Оголошенняфункційможнавиконатиузаголовномуфайлі, наприкладзім`ям"Attention.h":

1:#include <stdio.h>

2:#include <ctype.h>

68

3:#define FALSE 0

4:#define TRUE 1

5:int User Quits(void);

6:void present(void);

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

#include "Attention.h"

Якщо функція повинна повернути те чи інше значення, в залежності від однієї або кількох умов, можна використовувати , наприклад, такий псевдокод:

оператор_типу ім`я_функції (void)

{

if (умова)

return значення_1; блок_операторів return значення_2;

}

або подібна конструкція із інших операторів управління (if-else, switch і т.п.) - дивіться функцію in_upper() в попередньому прикладі.

5.3. Інші типи функцій.

Функції можуть повертати значення інших типів, які було розглянуто раніше. Для цього потрібно оголошувати прототип функції так:

оператор_типу ім`я_функції (void);

Наприклад:

float Any_Float_Fun (void);

long double Any_Long_double_Fun (void);

Попередження!

Функції, у яких немає прототипу, повертають значення цілого типу, навіть якщо в заголовку функції вказано інший тип.

Старий стандарт ANCI C не має прототипів функцій!

5.4. Модифікатори типів змінних у функціях.

5.4.1. Локальні змінні.

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

1:...

2:int global value;

3:main ()

4:{

5:int local value;

6:...

7:}

слідує, що будь-які оператори можуть звертатися до змінної global_value , а до змінної local_value можна звертатися тільки всередині функції main ().

Наприклад, яка-небудь функція може оголосити змінну:

1:int any function(void)

2:{

3:int local value = 12;

69

4:global value = 24;

5:...

6:}

При цьому змінна local_value в any_function() - це зовсім інша змінна, ніж у функції main (), а присвоєння змінній global_value призведе до того, що вона одержить значення 24.

Область дії змінних, описаних в різних частинах програми, називається областю видимості. Поза межами своєї області дії змінної ніби не існує.

Локальні змінні запам`ятовуються в стеці разом з адресами повернення із функції. Локальні змінні також називаються автоматичними змінними, оскільки вони виникають і зникають автоматично - по мірі виклику, виконання і закінчення роботи функцій. Можна оголошувати локальні змінні як автоматичні:

auto int local_value = 12; ,

але в цьому немає необхідності - вони є такими по замовчанню.

Якщо вам потрібно щоб локальна змінна, одержавши своє перше значення далі не змінювалась, вам потрібно оголосити її константою таким чином:

1:int any function(void)

2:{

3:const int local value = 12; .

4:...

5:local value = 13;

6:}

Вцьому випадку при обробці рядка 5 компілятор повідомить про помилку.

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

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

1:int any function(void)

2:{

3:...

4:if (умова) {

5:int i;

6:оператори в яких є змінна і

7:}

8:...

9:}

Вцьому випадку змінна і буде створена тільки тоді, коли буде виконана умова в

операторі if, і область її дії буде в наборі операторів до закритої фігурної дужки оператора if.

5.4.2. Глобальні змінні.

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

1:# include <stdio.h>

2:int globalint;

3:double globaldouble;

4:main ()

5:{

6:...

7:}

Глобальні змінні доступні з будь-якої точки програми. Тобто, одна функція може записати в таку змінну значення, а інша – прочитати її. Це один із способів обміну даними між функціями в програмі.

70

5.4.3. Регістрові змінні.

Регістрові змінні запам`ятовуються безпосередньо в регістрі процесора. register int count_register;

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

Значення, які запам`ятовуються в регістрах, обробляються безпосередньо інструкціями в машинних кодах, що прискорює виконання програми.

Рекомендація.

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

запам`ятовування інших невеликих значень, які визначають швидкодію вашої програми.

Необхідні установки в Borland Turbo C++ 1.00 можна виконати вибравши пункт меню

Compiler <Optimizations...> Optimization Options і після цього вибрати необхідне в меню найнижчого рівня:

Register Variables:

( ) None - При виборі цієї опції регістрові змінні заборонені - ця опція корисна для налагодження програм;

( ) Register keyword - Ця опція призводить до того, що регістрові змінні будуть використовуватись тільки тоді, коли вони явно описані в програмі (якщо, звичайно доступний регістр));

(•) Automatic - Ця опція дозволяє компілятору самому вибирати – розміщувати змінні в регістрах чи ні.

Більш докладну інформацію про інтегроване середовище та його настройку дивіться четверту частину комплексу методичних вказівок.

5.4.4. Змінні класу volatile.

Змінні класу volatile (непостійні) є антиподом регістрової змінної. Вона потрібна для того, щоб задати, що локальна змінна гарантовано не повинна розміщуватись в регістрах:

volatile int counting;

Крім того, це ключове слово забороняє компілятору будь-яку оптимізацію, пов`язану з цією змінною.

5.4.5.Зовнішні змінні.

Вбагатофайлових програмах функціям одного модуля1 може знадобитися звертання до змінних, які визначено в іншому модулі. Змінні, які визначено зовні модуля, в якому вони використовуються, називаються зовнішніми змінними. Взагалі вони не відрізняються від глобальних змінних. Нехай в модулі А визначено змінну

int outsider;

Якщо функція в іншому модулі, наприклад В, захоче використати цю змінну то ця функція повинна повідомити компілятору, що ця змінна визначена як зовнішня. Це можна зробити, попередивши оголошення специфікатором класу пам`яті extern:

extern int outsider;

Нижче приведено приклад основної програми:

1 Тут під модулем розуміється об’єктний модуль (object module). Програмна одиниця, яка є результатом трансляції або компіляції і придатна для обробки її редактором зв’язків (компоновщиком); програмний модуль, одержаний в результаті трансляції вихідної програми.

71

Приклад 5.3

"Extern 1.C"

1:

# include <stdio.h>

7:

{

2:

 

8:

Get Float();

3:

void Get Float(void);

9:

printf("Значення зовнішньої дійсної

4:

float f;

10:

return 0;

5:

 

11:

}

6:

main()

12:

 

Запускати цей програмний модуль на компіляцію не можна - потрібен ще один модуль, в якому визначено функцію Get_Float(). Далі приведено його код:

Приклад 5.4

"Extern 2.C"

1:

# include

<stdio.h>

6:

Get Float();

2:

 

 

7:

printf("Введіть значення дійсної змінної f:\n");

3:

void Get

Float(void)

8:

scanf("%f",&f);

4:

{

 

9:

}

5:

extern float f;

10:

 

Ключове слово extern у файлі "Extern_2.C" (приклад 6.4) повідомляє компілятору, що пам`ять для змінної f виділена десь в іншому місці. Виділяє цю пам`ять компоновщик, коли об`єднує нарізно скомпільовані модулі.

5.4.6. Статичні змінні.

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

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

1:void Any Fun(void)

2:{

3:static int final count = 1;

4:...

5:}

Компілятор відводить для змінної final_count постійну область пам`яті (в сегменті даних програми) і ініціює її значенням рівним 1 один раз - при першому виклику функції Any_Fun(). Надалі змінна final_count при наступних викликах функції Any_Fun() буде мати те значення, яке вона мала після попереднього завершення роботи функції.

Примітка!

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

Приклад:5.5

 

 

 

 

 

 

 

 

 

 

"STATIC.C"

 

1:

# include <stdio.h>

16:

printf(" %d",Next 2());

2:

 

 

17:

return 0;

3:

int Next

1(void);

18:

}

4:

int Next

2(void);

19:

 

5:

 

 

20:

int Next 1(void)

72

6:

main()

 

 

 

 

 

 

 

21:

{

7:

{

 

 

 

 

 

 

 

 

 

22:

static int value = 1;

8:

int i;

 

 

 

 

 

 

 

23:

return value++;

9:

 

 

 

 

 

 

 

 

 

 

24:

}

10:

printf(" \n Виклик Next

1():\n");

25:

 

11:

for (i = 1; i <= 10; i++)

 

26:

int Next 2(void)

12:

printf(" %d",Next

1());

 

27:

{

13:

 

 

 

 

 

 

 

 

 

 

28:

int value = 1;

14:

printf(" \n Виклик Next

2():\n");

29:

return value++;

15:

for (i = 1; i <= 10; i++)

 

30:

}

 

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

 

 

 

Виклик Next_1():

9

10

 

 

 

1

2

3

4

5

6

7

8

 

 

 

Виклик Next_2():

2

2

 

 

 

2

2

2

2

2

2

2

2

 

 

5.5. Параметри і аргументи функцій.

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

double cube(double r)

де: r - називається параметром.

Виклик функції матиме такий вигляд:

Abs = cube(z);

де: змінна дійсного типу z - називається аргументом функції (в окремому випадку може бути постійна).

Покажемо на прикладі цієї функції, як значення аргументу передається параметру функції (рис. 6.2).

Нагадуємо, що символічна константа M_PI визначена у файлі math.h (там є рядок #define M_PI 3.14159265358979323846), тому для її використання в програмі потрібна директива

#include <math.h>

 

Значення, яке повертає-

# include <math.h>

ться, присвоюється змін-

double cube(double);

ній Abs

main ()

{

double Abs, z = M_PI; Abs = cube(z);

return 0;

}

 

double cube(double r)

Аргумент z передається

по значеннюпараметру r

{

return r*r*r;

}

Параметр дорівнює значенню переданого аргументу

Рис. 5.2. Схема передачі аргументів функції по значенню

Функції можуть оголошувати кілька параметрів. В цьому випадку оператори можуть передавати їм кілька аргументів. Наприклад:

/* Оголошення прототипу функції */

double Cost(double, double, double)

/* Виклик функції */ result = Cost(10.0, 100.0, 0.068);

/* Заголовок функції */ double Cost(double t_time, double p_power, double r_rate)

{

73

return r_rate * (p_power * 0.001 * t_time);

}

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

1:int time;

2:double, double rate;

3:time = 10;

4:power = 100.0

5:rate = 0.068;

6:result = Cost(time, power, rate);

7:...

то, присвоєння t_time = time;

p_power = power; r_rate = rate;

приводить до того, що значення time рівне 10, перетворюється до значення 10.0 і присвоюється t_time.

Попередження!

Краще, щоб типи аргументів і параметрів співпадали тому, що перетворення проводиться для сумісних типів. Якщо параметр має цілий тип, а рагумент - рядковий, то компілятор видасть повідомлення про помилку: "Type mismatch..."(Невідповідність типів).

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

1:...

2:main()

3:{

4:...

5:result = Cost(time, power, rate);

6:...

7:}

8:

9:double Cost(double t_time, double p_power, double r_rate)

10:{

11:t_time = t_time + 12;

12:return r_rate * (p_power * 0.001 * t_time);

13:}

то гарантується незмінність значення змінних time, power, rate, не дивлячись на те, що значення змінної t_time збільшується на 12. Адже дії виконуються над копією змінної time.

5.5.1. Параметри - покажчики.

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

1:int time;

2:...

3:result = Cost(&time, power, rate);

5:double Cost (double *t_time, double p_power, double r_rate); /* Заголовок */

74

6:{

7:return rate * (power * 0.001 * (*time));

8:}

5.5.2.Модифікатори параметрів.

Оскільки параметри функцій є використовуючи модифікатори пам`яті чином:

локальними змінними, то їх можна оголошувати, register, volatile і const. При оголошенні функції таким

void Any_Fun(const int x, const int y, register int value);

оператори можуть передавати значення аргументів параметрам x та y, але модифікатори const не дадуть операторам всередині функції змінювати їх значення. Ціла змінна value може розміщуватись в регістрі (якщо він буде доступний). Регістрові параметри передаються як звичайно через стек, і звідти копіюються в регістр. Якщо регістр недоступний, то вони обробляються як звичайні параметри.

5.6 Прототипи функцій з іменованими параметрами.

Прототипи функцій можуть мати такий вигляд:

1:double Cost(double t_time, double p_power, double r_rate);

або

2:double Cost(double, double, double);

Перший рядок має іменовані параметри в прототипі, а другий має неіменовані параметри. Ці дві форми запису еквівалентні, оскільки компілятор ігнорує імена параметрів в

прототипі.

Але заголовок обов`язково повинен мати імена прототипів.

Інколи можна зустріти іншу форму завдання параметрів - старий стиль, прийнятий в версії засновників мови Сі - Кернігана і Рітчі:

double Cost (double, double , double ) /* Заголовок */ double time; /* Опис 1-го параметра */

double power; /* Опис 2-го параметра */ double rate; /* Опис 3-го параметра */

{

return rate * (power * 0.001 * time);

}

Але на відміну від ANCI C такий заголовок призводить до того, що компілятор не проводить перевірку на відповідність типів параметрів та аргументів, що може призвести до помилок, які важко визначити. Сучасні компілятори підтримують ці погодження для того, щоб підтримати сумісність з старими програмами.

5.7. Рекурсивні функції

Мова програмування дозволяє, щоб функція викликала сама себе прямо або побічно. Цей процес називається рекурсією. Функція є побічно рекурсивною, якщо вона має прямий або побічний виклик іншої функції, яка в свою чергу, має прямий або побічний виклик першої функції. Якщо в тілі функції явно використовується виклик цієї ж самої функції, то це буде пряма рекурсія (або функція, яка викликає сама себе: self-calling).

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

Для знайомства з рекурсією розглянемо приклад.

75

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