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

Зубенко, Омельчук - Програмування. Поглиблений курс

.pdf
Скачиваний:
58
Добавлен:
07.03.2016
Размер:
5 Мб
Скачать
☆

Розділ ІІІ. МОВИ ПРОГРАМУВАННЯ С ТА С++

Таблиця 3.11. Унарні перетворення

Тип операнда

 

С99: тип результату

Традиційна С:

 

тип результату

 

 

 

float

 

Без перетворення

double

Масив типу Т

 

Покажчик типу Т

Так само

Функція зі значенням типу Т

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

Так само

 

 

зі значенням типу Т

 

Цілий не нижчий ніж int

 

Без перетворення

Так само

Цілий нижчий ніж int

 

Int

Так само

Беззнаковий нижчий ніж

,

int

unsigned int

але зі значенням у int

int

 

 

 

 

 

Беззнаковий нижчий ніж int,

unsigned int

Так само

але зі значенням поза int

 

 

 

Бінарні зведення. У процесі бінарних перетворень над кожним з операндів спочатку здійснюються унарні перетворення, у результаті яких збільшуються розміри коротких значень, а імена масивів і фун- кцій перетворюються на покажчики. Потім здійснюються необхідні зведення операндів до типу виразу.

Зведення фактичних параметрів функцій. Фактичні параметри зводяться до типу формальних параметрів згідно з прототипом функції. Жодні інші правила не діють. У С99 передбачено окремий набір станда- ртних функцій для кожного з типів float, double та long double.

Приклад 3.26. Зведення арифметичних типів:

1:int i;

2:char ch;

3:float f;

4:void func(void)

5:{

6:ch=i; /*int--->char*/

7:i=f; /*float--->int*/

8:f=ch; /*char--->float*/

9:f=i; /*int--->float*/

10:}

У шостому рядку цього прикладу старші двійкові розряди цілої змінної i відкидаються, а у ch заносяться молодші 8 бітів. Якщо зна- чення i лежить в інтервалі від 0 до 255, то значення ch та i будуть однаковими, при цьому інформація не втрачається. Інакше у ch бу- дуть занесені тільки молодші розряди змінної i. У сьомому рядку в i буде записана ціла частина числа f; у восьмому – відбудеться пере- творення цілого числа, що зберігається у ch, на число в плаваючому форматі; у дев'ятому – те саме, тільки з 16-розрядним цілим ■

311

ПРОГРАМУВАННЯ

Примусове зведення типів. Здійснює операція (Т)e , яка значен- ня виразу e перетворює до типу Т. Наприклад, унарна операція (float) як старша щодо ділення перетворює нульове значення цілого виразу 1/3 до значення (float) 1/3=0.333333.

Приклад 3.27. У наведеній програмі ця ідея використана для збе- реження точності при виведенні результатів обчислення:

#include <stdio.h>

int main(void) /*друкування і*і/3 із дробовою частиною*/

{

int i;

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

printf("%d/3=%f\n",i,(float)i/3);

return 0;

}

Без операції примусового зведення (float) виконувалося б цілочис- лове ділення ■

*Література для CР: вирази – [55, 102, 132, 133, 136]; особли-

вості арифметичних операцій стандартних типів [19, 60]; пере- творення типів – [55, 133].

Контрольні запитання та вправи

1.Що таке вираз?

2.Що таке ліва й права асоціативність?

3.Що таке l-вираз?

4.Що таке r-вираз?

5.Які бувають r-вирази?

6.Що таке первинний r-вираз?

7.Як обчислюються значення виразу-присвоювання?

8.Що таке базовий і похідний типи?

9.Який вигляд має ціла константа?

10.Який вигляд має дійсна константа?

11.Який вигляд має символьна константа?

12.Перерахувати й визначити унарні й бінарні арифметичні операції.

13.Перерахувати й визначити унарні й бінарні логічні операції.

14.Який вигляд має опис стандартної змінної?

15.Який вигляд має символьна константа?

16.Що таке модифікатор знака змінної цілого типу?

17.Перерахувати розміри змінних цілих типів.

18.Перерахувати типи дійсних змінних.

312

Розділ ІІІ. МОВИ ПРОГРАМУВАННЯ С ТА С++

19.Що таке умовні й послідовні вирази?

20.Що виведе такий фрагмент програми:

1){int x =011, y = 9, z = 4; printf("%d\n", x|z<<y);}

2){int x, y, z; x = y = z = 1; ++x || ++y && ++z;

printf("%d\t%d\t%d",x,y,z);}

printf("%d\n",

3){int x =011, y = 9, z = 5;

x<=y ? x&~z:z&y);}

 

4){int x,y,z; x = y = z = 1; x++ && ++y ||

++z;printf("%d\t%d\t%d",x,y,z);}

x <<= y;

5){int

x = 8, y = 3, z

= 1;

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

x++ && ++y && ++z;

6){int

x,y,z; x = y = z = -1;

printf("%d\t%d\t%d",x,y,z);}

 

 

7){int x =011, y = 9, z = 4; printf("%d\n", x | y ^y );}

8){int x, y, z; x = y = z = 1; ++x && ++y || ++z; printf("%d\t%d\t%d",x,y,z); }

9){int x = 8, y =3, z =1;printf("%d\n",z += x < y

? x ++ : y ++ );

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

z >=

y

10){int x =8, y =3,

z =1;

printf("%d\n",

>= x ? 1 : 0 ); }

=3,

z

=1;

y

>>=

x;

11){int x =8, y

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

 

 

printf("%d\n", x

12){int x =05, y = 02, z = 01;

^y & ~z ); }

21.Який вигляд має опис порядкової змінної?

22.Що таке тип void?

23.Визначити порядок на числових типах за діапазоном їхніх значень.

24.Як знайти розмір змінної?

25.Що таке сумісні й угоджені типи?

26.Чи сумісні (узгоджені) пари типів:

int та signed int; char та unsigned char; float та double;

short та int ?

27.Сформулювати правила зведення: а) двох цілих типів; б) двох дійсних типів; в) цілого й дійсного типів; г) типів у операціях присвоювання.

28.Що таке унарні й бінарні зведення?

29.Як зводяться фактичні параметри функцій?

30.Що таке примусове зведення типів?

31.Нехай a, b, c – імена цілих змінних. Написати арифметичний (не умовний) вираз, значенням якого є: а) більше з двох зна- чень a та b; б) значення останньої цифри в десятковому по-

313

ПРОГРАМУВАННЯ

данні a (напр., при a =125 – це 5); в) сума значень цифр дво- значного a (при a = 39 – це 12 ); г) сума значень цифр три- значного a (при a = 214 – це 7 ).

32.Нехай a , b , c , d , e , a1 , b1 , c1 та a2 , b2 , c2 – імена цілих

змінних із додатними значеннями. Написати умовний вираз, значенням якого є 1 тоді й тільки тоді, коли: а) a , b , c мають однакові значення; б) a , b , c задають сторони трикутника; в) a , b , c задають сторони прямокутного трикутника; г) a , b , c задають сторони гострокутного трикутника; д) a , b , c задають сторони рівнобедреного трикутника; е) a , b , c за- дають сторони різнобічного трикутника; є) a , b , c , d зада- ють сторони паралелограма; ж) a1 , b1 , c1 та a2 , b2 , c2 за-

дають сторони двох рівних трикутників; з) цеглину a ×b ×c можна просунути в прямокутне вікно d ×e так, щоб її грані були паралельні сторонам вікна.

33. Написати вираз, значенням якого є 1 тоді й тільки тоді, коли дві прямі, задані цілими коефіцієнтами рівнянь ви- гляду ax +by +c = 0 : а) паралельні й не збігаються;

б) паралельні (можливо, збігаються); в) збігаються; г) пере- тинаються; д) перпендикулярні.

34.Підлога в кімнаті складається з клітин і має розмір n × m. На двох клітинах поставлено стовпи. Написати вираз, яким задається

ознака того, що підлогу можна покрити дошками розміром 2×1.

35.Написати послідовність виразів-присвоювань, що здійснює обмін значеннями двох змінних за умови: а) можна викори- стовувати третю змінну; б) третю змінну не використовува- ти, але змінні числові.

36.Дано дійсні змінні x,y,z . Написати вираз для обміну їх зна- ченнями згідно з перестановкою: а) xyz ; б) xyz ; в) xyz ,

zxy yzx yzx

не використовуючи четверту змінну.

37. Нехай x – числова змінна. Використовуючи лише операції множення й присвоювання, обчислити значення степеня з мінімальною кількістю множень. Наприклад, обчислення x6 можна задати так: x2 = x * x , x4 = x2 * x2 , x4 * x2.

а) x10 ;

д) a5 та a19 ;

з) a4 та a20 ;

й) a28 .

б) x12 ;

е) a15 ;

и) a5 та a13 ;

 

в) x16 ;

є) a21 ;

і) a2 , a5 , a17 ;

 

г) x32 ;

ж) a64 ;

ї) a4 , a12 , a28 ;

 

314

 

Розділ ІІІ. МОВИ ПРОГРАМУВАННЯ С ТА С++

38. Дано дійсне

x . Написати вираз для обчислення значення

багаточлена

2x4 − 3x3 + 4x2 −5x + 6 . Мінімізувати кількість

операцій у виразі.

39. Дано дійсні числа x,y,z . Написати арифметичний (не умо-

вний) вираз для отримання: а) max (x,y); б)

min(x,y );

в) max (x + y + z,xyz ); г) max2 (x +y +z /2,xyz )+1;

д) sign(x) .

Допустимою є також функція модуль abs(x ).

40. Функція color(x, y) визначає колір поля xy на шаховій дошці 8×8:

//0 - білий колір, 1 - чорний колір int color(char x,int y)

{return odd(c(x))?odd(y)?1:0:odd(y)?0:1;}

Допоміжна функція int с(char x)) перетворює символи

'a', 'b', 'c', 'd', 'e', 'f','g','h' відповідно на числа 1, 2, 3, 4, 5, 6, 7, 8, а функція int odd(int n) пере- віряє число n на непарність (1 – непарне, 0 – парне). Як правильно розташувати дужки в умовному виразі операто- ра return? Запрограмувати функції с та odd.

41.Дано шахову дошку 8 ×8 і два поля xy та pq , подані в ша-

ховій нотації (див. вправу 11, підрозд. 1.3). Потрібно з'ясувати:

а) чи ці поля одного кольору;

б) чи загрожує ферзь на полі xy полю pq ;

в) чи загрожує кінь на полі xy полю pq ;

г) чи може тура з поля xy за один хід потрапити на поле pq ; якщо ні, то з'ясувати, як це можна здійснити за два

ходи (указати поле, на яке приводить перший хід);

д) чи може слон із поля xy за один хід потрапити на поле pq ; якщо ні, то з'ясувати, як це можна здійснити за два

ходи (указати поле, на яке приводить перший хід);

е) чи може король із поля xy за один хід потрапити на поле pq ; якщо ні, то з'ясувати, за скільки ходів це можна здійснити; є) чи загрожує слон із поля xy королю на полі pq ;

ж) чи загрожує тура з поля xy коню на полі pq , і навпаки.

Розв'язок оформити у вигляді функцій int f(char x,int y,char p, int q), тіла яких є послідовностями виразів присвоювань і умовних виразів.

315

ПРОГРАМУВАННЯ

3.3. Оператори

¾Базові оператори

¾Структуровані оператори

Ключові слова: оператор, базовий оператор, структурований опeрaтор, по- рожній oператор, oператор переходу, оператор із міткою, присвоювання, оператор виклику функції, ініціалізація параметрів і локальних даних, oператор-вираз, опера- тори продовження, переривання й виходу з функції, безумовний перехід, продовжен- ня, переривання, групове присвоювання, складений оператор, розгалуження, обхід, ітерація, повторення, структурний цикл, перемикач.

Оператори – це конструкції, що безпосередньо задають обробку даних у програмах (створюють нові дані або змінюють значення вже існуючих). З погляду семантики вони є X −Y -операторами оновлення (див. підрозд. 2.1.2). Композиційну будову операторів описують стру- ктурні схеми програм (підрозд. 2.5.1).

В операторних інтерпретаціях ССП станами є сукупності даних, а елементарними предикатами й перетвореннями – відповідно ариф- метичні вирази й базові X −Y -оператори оновлення. Загальна синта- ксична структура операторів виглядає так:

<oператор>::=<оператор-без-мітки>| <мітка>:<оператор-без-мітки>

<оператор-без-мітки>::=<базовий-оператор>| <структурований-опeрaтор>

<мітка>::=<ідентифікатор> <базовий-оператор>::=<порожній-oператор>|<oператор-вираз>| |<oператор-переходу>|<оператор-повернення>

3.3.1. БАЗОВІ ОПЕРАТОРИ

Усі базові оператори синтаксично закінчуються символом ‘;'. Порожній оператор. Не впливає на стан пам'яті. Однак, якщо йо-

го наділити міткою, то на нього можна передати керування в програ- мі за допомогою оператора безумовного переходу:

<порожній-oператор>::=;

Оператори-вирази. Це вирази, що закінчуються ‘;':

<oператор-вираз>::=<вираз>;

316

Розділ ІІІ. МОВИ ПРОГРАМУВАННЯ С ТА С++

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

1;

/*оператор, еквівалентний порожньому оператору*/

i++;

/*збільшує значення змінної i на 1*/

--k;

/*зменшує значення змінної i на 1*/

Основні X −Y -оператори мови С присвоювання й виклику функції є операторами-виразами. Вирази-присвоювання розглядалися в під- розд. 3.2.1, а виклики функцій – у підрозд. 3.1.3, 3.6.2. Груповим присвоюванням називається оператор присвоювання вигляду: x=y=…=e;, де x,y… – змінні, e – вираз. У результаті групового присво- ювання всі змінні ліворуч від виразу e отримують його значення.

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

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

Далі виконується модифіковане тіло функції (тіло функції після етапу ініціалізації параметрів і локальних даних).

Останній етап – вихід із функції. Вихід із функції, яка повертає ре- зультат, дещо відрізняється від виходу з функції, яка не повертає ре- зультат. У першому випадку вихід обов'язково здійснює оператор повернення:

return[<вираз-результат>];

у другому це може бути також автоматичний вихід після виконання останнього оператора в модифікованому тілі. У процесі виходу: а) припиняється доступ до автоматичної пам'яті, яка використовува-

30 У НМ для цього передбачено регістр J.

317

ПРОГРАМУВАННЯ

лася при виклику функції; б) у місце виклику повертається результат (якщо вихід здійснюється оператором return із виразом-результатом); в) у лічильник команд РС завантажується точка продовження.

Оператори переходу. Змінюють лічильник команд процесора (РС) і тим самим впливають на хід обчислень:

<oператор-переходу>::=<безумовний-перехід>|<продовження>| <переривання>|<вихід-із-функції>

Оператори в тілі функції можуть мати мітки, що належать до слу- жбових даних і є ідентифікаторами. Щоб описати мітку, достатньо поставити її перед оператором у певному блоці й відокремити від ньо- го символом ‘:'. Наприклад, {…L1: printf ("Error --1"); …}. Областю існування мітки як даного є блок, в якому вона описана. За допомо- гою мітки на її оператор може бути здійснена передача керування та ініційоване продовження виконання блока саме з даного оператора. Таку передачу керування здійснює оператор безумовного переходу:

goto <мітка>;

На операційному рівні оператору goto L; відповідає команда безумо- вного переходу, яка заносить у лічильник команд адресу першої з групи команд, що відповідають у машинному коді оператору з міткою L.

Оператори продовження continue; і переривання break; засто-

совуються в циклах (останній – і в перемикачах). Перший перериває поточний ітеративний крок внутрішнього циклу, у тілі якого перебу- ває, і примушує розпочати новий. Другий примусово перериває й закінчує виконання внутрішнього циклу або перемикача, у тілі якого він міститься.

Оператор виходу з функції return[<вираз-результат>] обчислює значення виразу-результату, перетворює його до типу результату фу- нкції, записує в поле результату, пересилає звідти в місце виклику й передає керування програмою за адресою поля продовження.

3.3.2. СТРУКТУРОВАНІ ОПЕРАТОРИ

Загальний вигляд:

<структурований-опeрaтор>::=<cкладений-оператор>| <розгалуження>| <обхід>| <перемикач>|

318

Розділ ІІІ. МОВИ ПРОГРАМУВАННЯ С ТА С++

<ітерація>| <повторення>| <цикл>

Складений оператор. Подається складеною регулярною схемою програм:

<cкладений-оператор>::=\{{<оператор>}\}

Дія складеного оператора зводиться до послідовного виконання операторів. Серед операторів можливі й оператори опису даних. У цьому випадку складений оператор називається блоком. Оператори опису визначають локальні дані блока.

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

<розгалуження>::=if(<цілий-вираз>)<оператор> else <оператор> <обхід>::=if(<цілий-вираз>)<оператор>

Допускається використання вкладених операторів розгалуження й обходу. Приклад 3.28. Наведений фрагмент ілюструє вкладені оператори

if-else:

char znac; int x,y,z;

…

if (znac= ='-')x=y–z;

else if (znac= ='+')x=y+z; else if (znac= ='*')x=y*z;

else if (znac= ='/')x=y/z; else printf("error");

…

■

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

Перемикач. Оператор-перемикач – це випадок регулярного детер- мінованого вибору detcase:

<перемикач>::=switch(<цілий-вираз>) {

case <цілий-вираз-конст1>:<оператор>…<оператор>…

319

ПРОГРАМУВАННЯ

[default:<оператор>…<оператор>]

…

case <цілий-вираз-констN>:<оператор>…<оператор>

}

Усі вирази-константи мають бути попарно різними. Варіант дій із випадком default може бути тільки один. У процесі виконання опе- ратора обчислюється значення цілого виразу й порівнюється з кож- ною case-константою. Якщо знаходиться варіант зі збігом значень, то далі послідовно виконуються оператори даного варіанта й усіх насту- пних. Якщо жодна із case-констант не знайдена, то керування пере- дається на default за умови, що він є в конструкції. Інакше викону- ється порожній оператор. У тілі оператора switch можна використо- вувати вкладені оператори-перемикачі.

Щоб у перемикачі забезпечити виконання операторів тільки одного варіанта, у кінці кожного з варіантів розміщують оператор перери- вання break;, який примусово завершує роботу перемикача.

Приклад 3.29. Перепишемо фрагмент коду з прикл. 3.28 із вико- ристанням перемикача:

char znac; int x,y,z;

switch (znac)

{

case'+':x=y+z; break; case'-':x=y–z; break; case'*':x=y*z; break; case'/':x=u/z; break; default:printf("error");

}

■

Ітерація, повторення і структурний цикл. Перші два цикли по-

даються регулярними схемами програм ітерації й повторення:

<ітерація>::=while(<умова>)<оператор> <повторення>::=do<оператор> while (<умова>)

Умовою повторення оператора є ненульове значення цілого виразу. На відміну від ітерації тіло оператора повторення завжди виконуєть- ся принаймні один раз.

Структурний цикл має вигляд:

320