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

Вакал - Мова Сі (Типи данних та основні структури керування)

.pdf
Скачиваний:
15
Добавлен:
07.03.2016
Размер:
460.57 Кб
Скачать

оператори, які відносяться до інших міток (поки не зустрінеться оператор

break).

Приклад:

#include <stdio.h> main( )

{

char c;

printf(²введіть символ:²); scanf(²%c²,&c);

switch(c) {

case ‘A’: printf(²вибір А\n²);break; case ‘B’: ;

case ‘C’: printf(²вибір В або С\n²);break;

default: printf(²Не вибрано ні A, ні В і ні С\n²);break;

}

}

Приклад:

#include <stdio.h> main( )

{

char sign;int x,y=4,z=2; printf(²введіть символ з клавіатури:²); sign=getch( );

switch(sign) {

case -’: x=y-z; printf(²x=%d\n²,x);break; case +’: x=y+z;

case *’: x=y*z;

case ‘/’: x=y/z; printf(²x=%d\n²,x);break; default: printf(²Невідомий оператор\n²); }

}

3.11. Цикли

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

поки F повт

 

повт

 

P

(Lw)

P

(Lu)

кц;

 

до F кц;

 

цикл

 

для k =1 до c крок h повт

P

 

P

(Lс)

 

 

31

 

якщо F то вихід; (Le)

кц;

Q

 

кц;

 

Розглянемо реалізацію цих циклів у мові Ci. Зауважимо перш за все, що у Ci, також як і у мові Паскаль, є три типи циклів: цикл з умовою повторення, цикл з умовою закінчення, цикл з лічильником.

3.11.1. Цикл з умовою повторення (продовження, з передумовою)

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

Оператор циклу WHILE має формат: WHILE <вираз>

<оператор>;

де <вираз> – будь-який допустимий у Ci вираз, який приймає нульове або відмінне від 0 значення, а <оператор> може бути порожнім, простим або складеним. В останньому випадку він заключається в операторні (фігурні) дужки.

Схема виконання оператору WHILE:

1.Обчислюється значення <виразу>.

2.Якщо воно Хибне (дорівнює 0), то тіло оператору WHILE не виконується, цикл завершується і керування передається на наступний за циклом оператор програми.

3.Якщо воно Істинне (тобто не дорівнює 0), то виконується <оператор>, тобто тіло циклу.

4.Процес повторюється за цією ж схемою.

5.Цикл завершує роботу у випадках: <вираз> набув значення 0 (став Хибним); зустрівся оператор break, що передає керування на наступний за циклом оператор. Важливо запобігти можливість виконання циклу нескінченну кількість разів, що ілюструє наступний приклад:

#include <stdio.h> main( )

{

int index; index=1;

while (index5)

printf(²значення індексу=%d\n²,index);

}

Програма буде друкувати це повідомлення нескінченну кількість разів. Легко виправити цю помилку:

#include <stdio.h> main( )

{

int index; index=1;

while (index5)

32

{

printf(²значення індексу=%d\n²,index); index++;

}

}

Дії з перевірки виразу і прирощенню значення лічильника можуть бути поєднані в один вираз, використовуючи операцію збільшення на 1 ++.

#include <stdio.h> main( )

{

int index; index=1;

while (index++£5)

/*Значення index порівнюється з 5, а потім збільшується на 1 */ printf(²значення індексу=%d\n²,index);

}

Приклад:

/* Обчислення степеню */ #include <stdio.h>

main( )

{

double x,y=1; unsigned n,k; printf("Введіть x,n:"); scanf("%lf %u",&x,&n); k=n;

while (k >0)

{

if (k % 2 == 0)

{

k/=2; x*=x;

}

else

{

k--; y*=x;

}

};

printf("Степінь дорівнює %.2f \n",y);

}

3.11.2. Цикл з умовою закінчення (з післяумовою)

Формат циклу з післяумовою можна представити у вигляді

DO

<оператор>; WHILE (<вираз>);

Основна відмінність між циклами WHILE і DO ... WHILE полягає в тому, що <оператор> всередині DO ... WHILE завжди виконується хоча б один раз, оскільки перевірка умови виконання циклу здійснюється після виконання послідовності операторів, які складають тіло циклу.

33

Цикл DO ... WHILE аналогічний циклу repeat … until мови Паскаль, проте існують дві основні відмінності:

1.Цикл DO ... WHILE виконується поки <вираз> істинний (тобто не 0). Якщо вираз стає хибним (тобто рівним 0), то управління передається наступному оператору програми. У Паскалі цикл repeat ... until виконується поки булевий <вираз> хибний до тих пір, поки він не стане істинним.

2.Оператор repeat ... until не вимагає використання операторних дужок begin ... end для складеного оператора. У циклі DO ... WHILE використання фігурних дужок для групи операторів, що складають тіло циклу, є обов’язковим.

На додаток зауважимо, що у Ci (на відміну від мови Паскаль) операції порівняння (<, > та ін.) мають більш високий пріоритет, ніж логічні (&&, ||). Це дозволяє не заключати кожний вираз порівняння у круглі дужки, як це робиться у мові Паскаль.

Приклад:

do {

printf(²введіть a:²); scanf(²%d²,&a); }

/*виконується, поки не введем число більше low і менше high */ while (a<low||a>high);

Приклад: Знайти найлівішу цифру заданого натурального числа.

/* Обчислення першої цифри числа */ #include <stdio.h>

main( )

{

unsigned n,k; printf("Введіть n:"); scanf("%u",&n);

do

{

k=n % 10; n/=10;

}

while (n > 0);

printf("Перша цифра дорівнює %u \n",k);

}

3.11.3. Цикл з лічильником

Цикл з лічильником FOR( ; ; ) є одним з основних видів циклу, який характерний для всіх універсальних мов програмування, включаючи Ci. Однак версія циклу FOR, яка використовується у Ci, має більшу потужність і гнучкість.

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

Оператор циклу FOR має такий формат:

34

FOR(<вираз1>;<вираз2>;<вираз3>) <оператор>;

Так само, як і у попередніх циклах, <оператор> у тілі циклу FOR може бути або порожнім, або простим, або складеним. В останньому випадку він береться у фігурні дужки.

Параметри циклу FOR знаходяться у круглих дужках і відокремлюються один від одного крапкою з комою. Кожний параметр займає свою певну позицію і означає:

<вираз1> – як правило задає початкове значення параметру циклу – це вираз ініціалізації; <вираз2> – визначає умову продовження циклу;

<вираз3> – визначає зміну параметрів циклу після кожного виконання тіла циклу.

Схема виконання оператору циклу FOR:

1)обчислюється <вираз1>. Це здійснюється тільки один раз, коли цикл for починає виконуватися;

2)обчислюється <вираз2>. Це здійснюється перед кожним можливим виконанням тіла циклу;

3)якщо значення <виразу2> Істина (не дорівнює 0), то виконується тіло циклу, тобто <оператор>.

4)обчислюється <вираз3> (після кожного виконання тіла циклу);

5)обчислюється <вираз2>;

6)як тільки значення <виразу2> стає рівним 0 (Хибним), то управління передається на оператор, наступний за оператором FOR.

Істотно, що перевірка умови завжди виконується на початку циклу. Це означає, що цикл FOR може не виконатися жодного раз, якщо <вираз2> зразу буде хибним.

Приклад:

#include <stdio.h> main()

{

int i;

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

printf("Квадрат числа %d=%d\n", i,i*i);

}

Цикл FOR часто використовується для реалізації у програмі затримки часу з метою узгодження швидкості реагування комп’ютера з можливостями сприйняття людиною FOR(n=1; n<=10000; n++); Тіло циклу – порожній оператор.

Оператор FOR – це цикл з передумовою: рішення, чи виконувати кожний раз тіло циклу, приймається до його проходження. Звідси випливає, що все, що можна здійснити за допомогою циклу WHILE, можна зробити і за допомогою циклу FOR. Для перетворення циклу WHILE у цикл FOR треба попередньо здійснити ініціалізацію деяких вибраних змінних і включити у тіло циклу

35

деякі оператори, що коректують їх значення. Тоді оператор FOR буде еквівалентний такій конструкції:

<вираз1>; while(<вираз2>)

{

<оператор>; <вираз3>;

}

Хоча цикл FOR на перший погляд дуже схожий з циклом FOR у мові Паскаль, він є набагато гнучкішим і потужним засобом, ніж у інших мовах. Ця гнучкість – наслідок способу використання <виразів1,2,3> у специфікації циклу FOR. До цього часу перший вираз використовувався для ініціалізації лічильника, другий – для завдання його граничного значення, третій – для збільшення його поточного значення. Існує багато можливостей його застосування.

1. Лічильник побудовано в порядку спадання:

for (n=10; n>0; n--)

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

2. Значення лічильника збільшується або зменшується на2,3,5 і т.д.:

for (n=2; n<60; n=n+13) / або *n++=13 */

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

3. Лічильник будується за допомогою символів:

for (ch=‘a’; ch<=‘z’; ch++)

printf("Величина кода ASCII для символа %c дорівнює %d\ \n", ch, ch);

При виконанні цього оператору будуть роздруковані усі букви від ‘a’ до ‘z’ разом з їх кодами у таблиці ASCII.

4.Замість перевірки умови, що накладається на число повторень – ітерацій, можна перевірити виконання деякої іншої довільної умови. Наприклад, у програмі видачі квадратів чисел замість умови i<=10; можна розглянути, наприклад, таку i*i<=625 for(i=0; i*i<=625; i++)

5.Значення величини, що визначає <вираз3>, зростає не в арифметичній, а в

геометричній прогресії:

for (x=1.0; x<150.0; x=x*1.1) /* або x*=1.1*/

printf("%.2fn",x);

6. <вираз3> є довільним правильно складеним виразом, значення якого буде змінюватися на кожній ітерації:

#include <stdio.h> main()

{

int x,y=55;

for (x=10; y<=75; y=5*x+++10) printf("xx=%d, y=%d\n",x,y);

}

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

7. Можна опускати один або більше виразів у круглих дужках (але при цьому

36

символи крапка з комою не можуть бути опущені):

опустивши <вираз1> і <вираз3>, ми перетворимо цикл FOR у цикл WHILE:

специфікація for(;<вираз2>;) еквівалентна опису while(<вираз2>);

опустивши <вираз2>, маємо значення порожнього умовного виразу завжди

 

1 (Істина), цикл буде виконуватися нескінченну кількість раз, наприклад,

for(;;)printf("Ну і цикл!\n");

8.<вираз1> необов’язково повинен ініціалізувати змінну, на цьому місті може стояти будь-який інший оператор. Слід тільки пам’ятати, що <вираз1>

виконується тільки один раз. Наприклад,

#include <stdio.h> main()

{

int i=1;

for (printf("Вводьте числа!\n"); i!=6;) scanf("%d",&i);

printf("Нарешті ввели те, що треба!\n");

}

Перше повідомлення друкується один раз, потім вводяться числа до тих пір, поки не введемо число 6.

9. Параметри, що входять до <виразів2,3>, можуть бути змінені при виконанні операцій у тілі циклу. Наприклад,

#include <stdio.h> main()

{

int n,delta; float sum=0.0;

for (n=1; n<10; n+=delta)

{

printf("Введіть delta=:"); scanf("%d",&delta); sum+=delta; printf("sum=%f\n",sum);

}

}

10. Гнучкість оператору FOR може бути збільшена за допомогою операції “,” – послідовне виконання команд, яка дозволяє вводити складені вирази у цикл FOR. Наприклад:

#include <stdio.h> main()

{

char *msg; int up,down; msg="Привіт";

for (up=1, down=9; up<10; up++, down--)

printf("%s:%2d растет,%2d зменшується! \n", msg,up,down);

}

<вирази2,3> складаються тут з двох виразів, що ініціалізують і модифікують змінні up, down. При використанні операції ‘кома’ гарантується,

37

що вирази, розділені, комою, будуть обчислені зліва направо. Приклад: обчислення степені y = x n :

/* Обчислення степеня */ #include <stdio.h> main()

{

double x,y; unsigned n,i; printf("Введіть x,n:");

scanf("%lf %u",&x,&n); /*Введення через пробіл. */

/* Для введення через кому – поставити кому між %lf і %u */ y=1;

for (i = 1; i <= n; i++) y*=x;

printf("Степінь дорівнює %.2f \n",y);

/* Формат виведення ціла_част.xx,де xx - дві цифри мантиси */

}

Приклад. Обчислити суму ряда, що складається з 15 доданків

1 + 1 + 1 + 1 + 1 + K 2 4 8 16

#include <stdio.h> main()

{

const int n=15; int i;

float sum,x;

for (sum=0.0,x=1.0, i=1; i<=n; i++,x*=2.0) {sum+=1.0/x;

printf("sum=%f, коли i=%d\n",sum,i);

}

}

Відповідь: sum=1.99999. Ця задача розв’язує так званий парадокс Зенона: випущена стріла ніколи не долетить до мети. Спочатку стріла пролітає половину відстані до мети (скажімо, за 1 сек), потім половину відстані, що залишилася (1/2), потім половину, що залишилося, тобто 1/4 і т.д. Повний час польоту 1+1/2+1/4+...

3.11.4. Цикл з виходом

У Ci цикла з виходом немає. Він кодується за допомогою нескінченного циклу WHILE за допомогою оператору break

while(1==1)

{

..............

if(...) break;

..............

}

Оператор завершення break припиняє виконання самого внутрішнього із операторів SWITCH, DO...WHILE, FOR і WHILE, які містять його. Після виконання оператору break управління передається оператору, наступному за

38

перерваним. Оператор завершення не можна використовувати у конструкціях if...else або в тілі головної функції main для виходу з неї.

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

/* Обчислення суми додатних членів послідовності */ #include <stdio.h>

main()

{

int n,s=0; while (1 == 1)

{

printf("Введіть черговий елемент:"); scanf("%d",&n);

if (n < 0) break; s+=n;

}

printf("Сума додатних елементів дорівнює %d \n",s);

}

3.12. Оператор CONTINUE

Перериває виконання тіла циклів WHILE, DO ...WHILE або FOR, тобто пропускає залишок цикла, передаючи керування на початок наступної ітерації (тобто виходу з циклу подібно Break не відбувається). Для циклів WHILE, FOR після цього починається новий крок, а для циклу DO ... WHILE перевіряється умова виходу, і якщо вона Істинна, виконується наступна ітерація.

Приклад:

#include <stdio.h> main()

{

int n;

for (n=0;n<100;n++)

{

if(n%2) continue; printf(%d\n,n);

}

}

3.13. Оператор GOTO

Хоча для написання структурованих програм не рекомендується використовувати оператори переходу, у Ci є оператор переходу GOTO. Формат оператору:

goto <мітка>;

<мітка>: <оператор>;

де <мітка> – це просто ідентифікатор, який має бути унікальним. Оператор goto передає управління на <оператор>, що відмічено <міткою>. Відмічений

39

оператор повинен знаходитися в тій же функції, що і оператор goto. Оператор goto може використовуватися для виходу із вкладених операторів управління. Єдиний обґрунтований випадок його використання – це вихід із вкладених циклів при знаходженні якихось помилок (застосування оператору Break дає можливість здійснити вихід лише з внутрішнього циклу).

3.14. Вказівники

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

Вказівник – це деяка змінна, яка містить адресу деяких даних, а не їх значення. За допомогою вказівника можна:

одержати доступ до різних комірок пам’яті з метою зміни їх значення, зчитування і т.д.;

створювати нові змінні в процесі виконання програми.;

одержати доступ до різних елементів структур даних (масиви, рядки, структури).

Оголошення вказівників здійснюється за допомогою символу “*”.

Приклад.

#include <stdio.h> main()

{

int i, *ipoint; ipoint=&i; i=421;

printf(зміст i :%d\n,i);

printf(значення за адресою :%d\n,*ipoint);

}

Тут i – ціла змінна, яка має значення типу int, ipoint – вказівник на цілу змінну, тобто ipoint містить адресу величини цілого типу.

У програмі вказівнику ipoint присвоюється адреса змінної i; ціле значення 421 присвоюється самій змінній i. Можна безпосередньо присвоїти *ipoint значення 421, тобто *ipoint=421; так як вирази *ipoint і i – суть одна й та сама комірка пам’яті. *ipoint – доступ до об’єкта, що здійснюється через покажчик з використанням операції * – розадресація.

Змінимо програму (динамічний розподіл).

#include <stdio.h> #include <alloc.h> main()

{

int *ipoint; ipoint=(int*)malloc(sizeof(int)); *ipoint=421;

printf(значення за адресою :%d\n,*ipoint);

}

Розглянемо роботу оператору ipoint=(int*)malloc(sizeof(int)):

40