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

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

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

sizeof(unsigned char));

printf("float занимает %d байта\n",sizeof(float)); printf("double занимает %d байта\n",sizeof(double)); printf("long double занимает %d байта\n",sizeof(long double));

3.3. Операції

Для формування та наступного обчислення виразів використовуються операції. За кількістю операндів, які беруть учать у операції, вони поділяються на три групи:

унарні операції;

бінарні операції;

тернарна операція.

Операція присвоювання в Ci може бути як унарною, так і бінарною.

3.3.1. Унарні операції

Унарні операції, реалізовані у мові Ci, наводяться в таб. 3.3.

 

Таблиця 3.3. Унарні операції

 

 

 

Знак операції

Найменування

 

-

унарний мінус

 

+

унарний плюс

 

~

обернений код

 

!

логічне заперечення

 

*

звернення за адресою

 

&

адресація

 

sizeof

визначення розміру

 

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

повинен мати цілий або дійсний тип.

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

Операція оберненого коду (~) виробляє двійкове доповнення свого операнду, тобто інвертує його внутрішній двійковий код. В бітовому представленні результату містяться 1 у всіх розрядах, де у операнду 0 і 0 в тих розрядах, де у операнду 1. Операнд повинен мати цілий тип. В операції беруть участь всі розряди, виділені для представлення числа, в тому числі і знаковий біт.

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

Зауважимо, що в Ci відсутній булевий тип даних: вирази, в яких необхідні булеві значення, інтерпретують значення 0 як хибне, а всі ненульові значення як істинні. Запереченням будь-якого ненульового числа буде 0, а запереченням нуля – 1.

21

Операція адресації (&) виробляє адресу змінної, яка є операндом операції. Якщо s – деяка змінна заданого типу, то &s є адресою, за якою у пам’яті розташована ця змінна. Типом результату операції є вказівник на тип операнду.

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

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

3.3.2. Бінарні операції

Бінарні операції, реалізовані у мові Ci, наводяться в таб. 3.4.

 

 

 

Таблиця 3.4. Бінарні операції

Знак операції

Найменування

*

/

%

мультиплікативні

+

-

 

адитивні

<<

 

>>

операції зсуву

<

>

<= >=

операції відношення

!=

==

 

&

|

^

порозрядні (побітові)

&&

||

логічні операції

,

 

 

послідовне виконання

Бінарні операції виконуються зліва направо. Вони поділяються на такі групи: мультиплікативні, адитивні операції, зсуву, операції відношення, порозрядні, логічні, послідовного виконання.

Мультиплікативні операції. До них відносять операції множення (*),

ділення (/), знаходження залишку від ділення (%). Операндами операції %

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

Адитивні операції. До них відносяться додавання (+) і віднімання (–).

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

Операнди при додаванні можуть мати цілий або дійсний тип. Крім того, один операнд може бути цілою величиною, а інший вказівником. У цьому випадку, якщо, наприклад, використовується вказівник p на тип type, то вираз (p+i) представляє собою адресу пам’яті (p+i*sizeof(type)), де sizeof(type) дає кількість байт, яку займає змінна типу type, а величина i*sizeof(type) є зміщенням адреси в межах виділеної пам’яті.

22

Операнди при відніманні можуть мати цілий або дійсний тип. Крім того, можливі ще дві комбінації операндів:

1.перший операнд є вказівником, а другий – цілим числом;

2.обидва операнди є вказівниками на один і той самий тип.

Коли ціла величина i віднімається від вказівника p, що вказує на тип type, то вираз (p-i) представляє адресу пам’яті (p-i*sizeof(type)), зсунуту вліво відносно початкової адреси, заданої у p. Новий вказівник адресує той самий тип даних, що і початковий вказівник.

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

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

Операції зсуву. Операції зсуву зсувають двійкове представлення першого операнду вліво (“<<”) або вправо (“>>”) на число біт, задане другим операном. Обидва операнди повинні бути цілими величинами. Тип результату є типом лівого операнду після перетворення. При зсуві вліво праві біти, які звільняються, встановлюються у 0. При зсуві вправо вільні ліві біти встановлюються у 0, якщо тип unsigned, в протилежному випадку вони заповнюються копією знакового біту.

Приклади:

Rez=12<<2; => Rez=48 (12=11002; 00001100 =>зсув на 2 позиції вліво

00110000=25+24=32+16=48).

Rez=12>>2; => Rez=3(12=11002; 00001100 =>зсув на 2 позиції вправо

00000011=21+20=3).

3.3.3. Операції відношення. Дозволяють порівнювати два значення, отримуючи результат в залежності від того, дає порівняння істину чи хибність. Якщо порівняння дає Хиб, то результат дорівнює 0, якщо значення Іст – результат 1. Тип результату int. Операнди у відношеннях можуть бути цілого і плаваючого типу, а також обидва операнди можуть бути вказівниками на один і той самий тип.

3.3.4. Порозрядні логічні операції. До них відносяться:

1)операція порозрядного логічного І (“&”);

2)операція порозрядного логічного АБО (“|”);

3)операція порозрядного виключаючого АБО (“^”).

Операнди повинні бути будь-якого цілого типу.

Операція “&” – значення виразу i1 & i2 містять 1 у тих розрядах, в яких значення однойменних розрядів i1 і i2 дорівнюють 1, а 0 – в усіх інших

23

розрядах.

Операція “|” – значення виразу i1 | i2 містять 1 у всіх розрядах, в яких i1 або i2 містять 1, 0 – в усіх інших розрядах.

Операція “^” – значення виразу i1 ^ i2 містять 1 у тих розрядах, в яких i1 і i2 мають різні двійкові значення, 0 – в усіх інших розрядах.

Приклад. i=15&1 == >i=1; 15=11112. 1111&0001=0001=1

i=15|1 == >i=15;

1111|0001=1111=15

i=15^1 == >i=14;

1111^0001=1110=14.

3.3.5. Булеві (логічні) операції

В Ci відсутній булевий тип даних: вирази, в яких необхідні булеві значення, інтерпретують значення 0 як “ Хиб”, а всі інші – як “ Іст”. До бульових операцій відносяться:

1)операція логічного І (&&)

2)операція логічного АБО (||)

Операнди логічних операцій можуть бути цілих, плаваючих типів, або вказівниками. Операнди ЛО обчислюються зліва направо. Якщо значення першого операнду достатньо, щоб визначити результат операції, то другий операнд не обчислюється. ЛО оцінюють кожний операнд з точки зору його рівності 0. Результат ЛО – 1 ( Істина) або 0 (Хибність). Тип результату - int.

Операція && дає значення 1, якщо обидва операнди мають ненульові значення. Якщо один з операндів дорівнює 0, то результат теж 0. Якщо значення першого операнду 0, другий операнд не обчислюється.

Операція || дає значення 0, якщо обидва операнди дорівнюють 0, якщо якийсь з операндів має ненульове значення, то результат 1. Якщо перший операнд має ненульове значення, лругий операнд не обчислюється.

3.3.6. Операція послідовного виконання

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

{int i,j;

for (i=1,j=20; i<=16;i=i+1,j=j+17) printf(²%3d %7d \n²,i,j);

}

Перші три рядка результату роботи програми матимуть вигляд

120

237

354

3.3.7. Умовна (тернарна) операція Формат операції: <операнд1>?<операнд2>:<операнд3>

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

24

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

Приклад: обчислення максимального значення змінних a i b. max=(a<=b)?b:a.

3.3.8. Операції збільшення і зменшення

Операції збільшення “++” і зменшення “—“ є унарними операціями присвоєння. Вони збільшують або зменшують значення операнду на 1. Операнд цілого або плаваючого типу збільшується або зменшується на 1. Тип результату відповідає типу операнду. Операнд адресного типу збільшується або зменшується на 1*sizeof(type), тобто на розмір змінної, адресу якої він містить.

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

Приклад:

main()

{ int x=0,y=0,z,w ; z=x++; w=++y; printf(); }

Після виконання першої операції: z=0;x=1;після другої – w=1; y=1.

3.4. Присвоювання

Умові Ci знак “=” не означає дорівнює. Він означає операцію присвоювання деякого значення. Наприклад, b=2, що означає b присвоюється значення 2. Символ “=” ми називаємо операцією присвоювання. В цій операції дія виконується справа наліво. Тому допустимим є присвоювання у вигляді x=y=z=5. У багатьох мовах таке потрійне присвоювання заборонене, у Ci це – звичайна практика.

Умові Ci є декілька інших операцій присвоювання:

складене присвоювання (комбіновані операції присвоювання); група операцій присвоювання, які поєднують просте присвоювання з

однією із бінарних операцій. Будь-який вираз <операнд1>= <операнд1> <операція> <операнд2> може бути замінений на <операнд1> <операція> =

<операнд2>.

Наведемо приклади таких скорочень: a=a±b скорочується до a±=b

a=a*b

a*=b

a=a/b

a/=b

a=a<<b

a<<=b

a=a>>b

a>>=b

a=a&b

a&=b

a=a|b

a|=b

a=a^b

a^=b

25

3.5.Вирази

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

Приклади: 4, -6, 4+21, a*(b+c/d), q>3, x=++q%3, q=7*2.

Кожний вираз у мові Ci має значення. Щоб визначити його, ми виконуємо операції у порядку, який визначається рівнем старшинства. Максимальний пріоритет мають виклик функції, операції у дужках, взяття елементу масива і елементу структури. Потім йдуть унарні операції: ~,!,*,&, ++,--,sizeof(). Потім мультиплікативні – *,/,%, адитивні – ±; зсуву – >>,<<; відношення, порозрядні &,^,|; логічні &&,||; умовна ?: ; просте і складене присвоювання; послідовне виконання (,) - операція кома.

3.6. Оператори. Складений оператор. Операторні дужки. Ланцюг.

Для представлення інструкцій служать оператори мови, які є основними будівельними блоками програми. Програма складається із сукупності операторів з додаванням деяких знаків пунктуації. Оператор є закінченою інструкцією для ПК. У мові Ci вказівкою на наявність оператора є символ “ крапка з комою”, що стоїть у кінці його. Тому l=4 це всього лише вираз (який може бути частиною великого виразу), але l=4; є оператором.

Оператори бувають простими і складеними.

Простий оператор закінчуються “;”. Простими операторами є оператори опису; оператори присвоювання; оператори виклику функцій; оператори управління; порожній оператор (складається лише з крапки з комою. При його виконанні нічого не відбувається. Використовується в операторах циклу і умовному операторі if, коли тіло оператору не потрібне, але за синтаксисом необхідно мати хоча б один оператор; при необхідності відмітити фігурну дужку міткою.)

Складений оператор представляє собою два і більше операторів, поєднаних за допомогою фігурних дужок, які відіграють роль операторних дужок begin ...

end у мові Паскаль. Він називається також блоком. У Ci блок має вигляд:

{<оператор1>;< оператор2>;...< операторN>;

Ця форма нагадує блок у мові Паскаль, але має 2 важливих відмінності:

1)у мові Паскаль ви не повинні ставити крапку з комою за останнім оператором блоку, а у Ci повинні;

2)у мові Паскаль після слова end повинна стояти крапка з комою, а у Ci

після фігурної дужки крапка з комою не ставиться.

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

3.7. Розгалуження

Нагадаємо, що структура керування розгалуження має вигляд

26

якщо F то P інакше Q кя;

У мові Ci вона реалізується з допомогою умовного оператору if ... else. Оператор if має такий формат

if (<вираз>) <оператор1>; else

<оператор2>;

Виконання оператору if починається з обчислення значення <виразу>. Далі виконання відбувається за наступною схемою:

якщо <вираз> істинний (приймає значення не 0), то виконується <оператор1> і керування передається на оператор, наступний за

<оператором2>.

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

Частина else <оператор2>; є необов’язковою частиною умовного оператору. Формат скороченої форми умовного оператору:

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

Уцій конструкції <оператор1> виконується тільки тоді, коли значення <виразу> відмінне від 0. Якщо це значення дорівнює 0, то <оператор1> пропускається і керування передається на наступний за <оператором1> оператор.

Утому випадку, коли в залежності від хибності або істинності <виразу> ми бажаємо використати більше одного оператору, застосовується складений оператор, тобто послідовність операторів у фігурних дужках через “;”.

Приклад:

if (b = =0)

printf(²відношення не визначене\n²); else {

ratio=a/b;

printf(²відношення дорівнює %f\n²,ratio);

}

Допускається використання вкладених операторів if: оператор if може вкладатися у речення if або у речення else іншого оператора if. Рекомендується використовувати у цьому випадку фігурні дужки. Якщо ж вони опущені, компілятор зв’язує кожне ключове слово else з найближчим if, для якого не має else.

Приклад:

/* Обчислення максимуму з трьох чисел */ #include <stdio.h>

main()

{

double a,b,c,max; printf("Введіть a,b,c:");

27

scanf("%lf %lf %lf",&a,&b,&c); if (a > b) max=a;

else max=b;

if (max < c) max=c;

printf("Максимум з a,b,c дорівнює %.2f \n",max);

}

3.8. Умовний терм

Умовним термом називається конструкція формату:

<вираз1>?<вираз2>:<вираз3>;

Якщо значення <виразу1> ненульове (Істина), то виконується <вираз2>, і весь вираз отримує його значення; інакше обчислюється <вираз3>, який і дає результат усьому виразу. Дана конструкція – скорочений спосіб запису одного з видів оператору розгалуження if ... else. В термінах умовного оператору її можна записати так:

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

<вираз3>;

Приклад:

/* Обчислення максимуму з трьох чисел */ #include <stdio.h>

main()

{

double a,b,c,max; printf("Введіть a,b, с"); scanf("%lf %lf %lf",&a,&b,&c); max=(a > b)? a: b;

max=(max < c)? c: max;

printf("Максимум з a,b,c дорівнює %.2f \n",max);

}

3.9. Найпростіше введення / виведення

У Ci є декілька функцій виведення – найпоширенішою з них є printf. Вона виводить інформацію на екран. Формат команди:

printf(<рядок_формату>, <об’єкт>, < об’єкт >,...);

Рядок_формату – це рядок, який починається і закінчується подвійними лапками “ ”. У ньому міститься інформація двох типів:

1.Символи, які друкуються текстуально.

2.Специфікації формату. Вони звичайно починаються з символу % і супроводжуються буквою, яка позначає тип даних, що виводяться, та спосіб їх перетворення. Для кожного об’єкту повинна бути одна специфікація формату.

Декілька специфікацій формату:

%d

ціле число;

%u

ціле число без знаку;

28

%ld

довге ціле;

%p

значення вказівника;

%f

число з плаваючою точкою;

%e

число з плаваючою точкою у експоненціальній формі;

%c

символ;

%s

рядок;

%x

ціле у 16-річному форматі;

%o

ціле у вісімковому форматі;

%lf

число з плаваючою точкою подвійної точності.

Можна задати ширину поля, вказавши її між знаком % і буквою. Наприклад, %6d – ширина поля для цілого 6 символів. Для чисел з плаваючою точкою може бути вказано також число цифр після коми. Наприклад, %4.2f – дві десяткові цифри після коми для поля шириною у 4 символи.

Наступні символи не є специфікацією формату, а є послідовностями управління (так званими esc-послідовностями):

\n

переведення рядка;

\a

звуковий сигнал;

\b

забій (повернення курсору на крок);

\f

переведення формату (або очистка екрану);

\r

повернення каретки (повернення курсору у початок того ж рядка,

в якому відбулося виведення);

\t

табуляція (курсор після виведення числа пропускає 8 позицій).

Інші функції виведення: puts i putchar.

Функція puts виводить рядок на екран з переходом на новий рядок. У ній не потрібно вказувати \n. Так puts(str); працює так само, як і функція printf(“% s\n”, str); Функція puts припиняє роботу, коли зустрічається “\0”- символ. Програми, які використовують printf, вимагають введення більшого числа символів і більшого часу для виконання. Використовуючи puts, можна зробити програму компактною і швидкою.

Функція putchar виводить на екран єдиний символ, переходу на новий рядок не відбувається. Функція putchar(ch) еквівалентна printf(“ % c”, ch);

У Ci є декілька функцій введення, найпоширенішою серед яких є scanf. ЇЇ формат

scanf(<рядок_формату>, <адреса>, <адреса>,...);

У рядку_формату, який обмежується подвійними лапками “ ”, використовуються ті ж самі специфікації формату, що і у функції printf. Проте scanf має одну істотну відмінність – об’єкти, які йдуть за рядком_формату, повинні бути адресами, а не значеннями. За цими адресами розміщуються дані, що вводяться.

Наприклад, scanf(“% d %d ”, &a,&b);– очікується введення через пропуск двох цілих чисел: перше буде присвоєне змінній a, друге – b. Функції scanf передаються адреси &a і &b.

Якщо ми бажаємо вводити числа через кому, слід вказати її у рядку_формату між двома специфікаціями %d , %d.

29

Для введення рядка може бути використана також функція gets, яка читає все, що ви вводите, до тих пір, поки не натискується клавіша <Enter>. У кінець рядка вона додає “\0”- символ. Наприклад: gets(name);

Вкажемо на одну значну відмінність між gets і scanf: scanf вводить усі символи до тих пір, поки не зустрінеться пропуск; кінець рядка і т.д. Навпаки gets зчитує будь-які символи, доки ви не натиснете <Enter>.

Функція getch читає єдиний символ з клавіатури, не виводячи його на екран. Вона не має параметра. Ця функція має тип char, тому її значення може бути безпосередньо присвоєне символу, тобто ch=getch();

Функція getchar читає єдиний символ з клавіатури, і виводить його на екран. Вона також не має параметрів і використовується аналогічно попередній функції: ch=getchar();

3.10. Конструкція вибору

Умовна операція і конструкція розгалуження if…else полегшують написання програм, у яких здійснюється вибір між двома варіантами. Проте інколи у програмі необхідно здійснити вибір із декількох варіантів. Вибір із множини різних варіантів здійснюється з використанням спеціального оператора вибору switch. Його загальний формат:

switch(<вираз>) {

case <константа1>: <оператори>; case <константа2>: <оператори>;

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

case <константаN>: <оператори>; default: <оператори>;

}

Значенням <виразу>, який йде за ключовим словом switch, повинна бути величина цілого типу, у тому числі символьного і типу переліку.

На відміну від мови Паскаль:

<константа> – це завжди єдине значення. У мові Паскаль в операторі вибору case за константі мітки можна було вживати список або діапазон значень;

<оператори> не беруться у фігурні дужки;

у Паскалі після виконання операторів певного варіанту управління передається на наступний за оператором вибору case оператор програми, у Ci після виконання операторів даного варіанту керування не передається в кінець оператору switch, продовжується виконання списку операторів до першого оператору break.

Ніякі дві константи у одному операторі switch не можуть мати однакові значення, тобто вони повинні бути унікальними. Крім операторів, відмічених case, може бути необов’язковий, відмічений ключовим словом default. <оператори> можуть бути порожнім оператором, містити один або декілька операторів. Для завершення даного варіанта необхідно використати оператор break. У протилежному випадку будуть послідовно виконуватися усі

30