Неактивна зіркаНеактивна зіркаНеактивна зіркаНеактивна зіркаНеактивна зірка
 

Розділ 1. Оператори та операції

1.1. Оператор присвоєння

Оператор присвоєння позначається символом дорівнює (=) і має такий формат:

<ім’я_змінної> = <константа або вираз>;

Він присвоює змінній певне значення-константу або обчислене значення виразу; при присвоєнні слід враховувати відповідність типів виразу та змінної.

У мовах С/С++, крім простого присвоєння, існують складені операції присвоєння (табл. 4.1).

                                                                                                                                  Таблиця 4.1.
                                                         Складені операції присвоєння

Оператор

Призначення

Скорочений запис

Повний запис

+=

присвоєння з додаванням

x += y

x = x + y

­– =

присвоєння з відніманням

x – = y

x = x – y

*=

присвоєння з множенням

x *= y

x = x * y

/=

присвоєння з діленням

x /= y

x = x / y

%=

присвоєння остачі від ділення цілих чисел

x %= y

x = x % y

<<=

присвоєння зі зсувом ліворуч

x <<= y

x = x << y

>>=

присвоєння зі зсувом праворуч

x >>= y

x = x >> y

&=

присвоєння з порозрядною операцією І (AND)

x &= y

x = x & y

|=

присвоєння з порозрядною операцією АБО (OR)

x |= y

x = x | y

^=

присвоєння з порозрядною операцією АБО-НЕ (XOR)

x ^= y

x = x ^ y

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

(f = x – y) > 0

і допускає багаторазове використання, наприклад:

a = b = c = x * y;

Цей вираз виконується справа наліво у такій послідовності:

1)    x * y;

2)    c = x * y;

3)    b = c;

4)    a = b;

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

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

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

Вирази можуть бути арифметичними, символьними та логічними.

Оператор-вираз може мати скалярний тип (chart, short, int, long, float, double, long double), тип вказівника або структури. Операція присвоєння може бути комбінованою, тобто значення виразу може бути присвоєно декільком змінним. Формат комбінованого оператора присвоєння: iд1=iд2=...=iдn=вираз;. Приклади операторів-виразів:

k++;

g-=2;

(a>b)?c=a:c=b;

c=a+b;

c+=a;

a=b=c=2;

1.2. Арифметичні операції

У мові С існують унарні, бінарні та тернарні операції, залежно від кількості операндів.

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

Арифметичні операції подані у табл. 4.2.

                                                                                                                                  Таблиця 4.2.
                                                               Арифметичні операції

Оператор

Опис

+

додавання

­–

віднімання

*

множення

/

ділення

%

остача від ділення цілих чисел

++

інкремент (збільшення на одиницю)

--

декремент (зменшення на одиницю)

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

Приклад 4.1.

int n = 49, m = 10, i, j, k, p;

i = n % m;         // результат: i = 9

j = n % (–m);      // результат: j = 9

k = (–n) % m;      // результат: k = –9

p = (–n) % (–m);   // результат: p = –9

Операція інкремент (++) додає одиницю до операнда, а операція декремент (--) віднімає одиницю від операнда.

Залежно від місця розміщення операції відносно операнда роз­різняють префіксну та постфіксну форми. У префіксній фор­мі операцію записують перед операндом (++i, --j), а в постфіксній – після нього (i++, j--). Значення змінної у префіксній формі спочатку змінюється (збільшується або зменшується на одиницю) і лише після цього ця змінна з її новим значенням використовується в арифметичному виразі. У постфіксній формі в цілому виразі використовується поточне значення змінної і лише після його обчислення значення змінної змінюється (збільшується або зменшується на одиницю).

Приклад 4.2.

int m = 1, n = 2;

int a = (m++) + n;         // результат: a=3, m=2, n=2

int b = m + (++n);         // результат: a=5, m=2, n=3

Приклад 4.3.

int i;

i = i + 1;

i += 1;

++i;

i++;

/* декілька способів збільшення змінної на одиницю */

   

int j;

i = 1;

j = i++ * i++;

/* порядок обчислень:

1) j=i*i; 2) i++; 3) i++.

Результати виконання програми: j=1, i=3  */

   

i = 1; j = ++i * ++i;

/* порядок обчислень:

1) ++i; 2) ++i; 3) j=i*i.

Результати виконання програми: i=3, j=9  */

   

i = 1;

j = i++ * ++i;

/* порядок обчислень:

1) ++i; 2) j=i*i; 3) i++.

Результати виконання програми: j=4, i=3  */

   

int k = 1, n;

n = k++;

/* порядок обчислень:

1) n=k; 2) k++.

Результати виконання програми: n=1, k=2  */

   

n = ++k;

/* порядок обчислень:

1) ++k; 2) m=k.

Результати виконання програми: k=3, m=3  */

   

int t = 1, z;

z = (t++)*5;

/* порядок обчислень:

1) z=t*5; 2) t++.

Результати виконання програми: z=5, t=2  */

   

int s = 2;

f = (++s)/3;

/* порядок обчислень:

1) ++s; 2) f=s/3.

Результати виконання програми: s=3, f=1  */

1.3. Перетворення типів

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

1.3.1. Неявне перетворення типів даних для бінарних операцій

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

char < short < int < long < float < double < long double.

Крім того, для  символьного i цілих типів діє правило вкладеності:

тип < unsigned тип.

1.3.2. Неявне перетворення типів даних для операції присвоєння

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

Таблиця 2

Правила неявного перетворення типів даних для бінарних операцій

Операнд2\Операнд1

char

short

int

long

float

double

long double

char

int

int

int

long

double

double

long double

short

 

int

int

long

double

double

long double

int

   

int

long

double

double

long double

long

     

long

double

double

long double

float

       

double

double

long double

double

         

double

long double

long double

           

long double

1.3.3. Явне перетворення типів

При явному перетворенні типів перед виразом у круглих дужках вказується ім’я типу до якого необхідно перетворити значення виразу:

(iм’я_типу) вираз;

Приклади явного перетворення типів даних:

float x, y;

int a=5, b=2;

x=a/b;             /* Результат x==2.0 */

y=(float)a/b;  /* Результат y==2.5 */

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

Загальні правила перетворення типів:

  • 1) операнди типу float перетворюються до типу double;
  • 2) якщо один операнд long double, то другий операнд перетворюється до цього ж типу;
  • 3) якщо один операнд типу double, а другий – float чи ціле число, то другий операнд перетворюється до типу double;
  • 4) операнди цілих типів char та short перетворюються до типу int;
  • 5) цілі операнди типу unsigned char та unsigned short перетворюються до типу unsigned int;
  • 6) якщо один операнд типу unsigned long, то другий цілий операнд перетворюється до типу unsigned long;
  • 7) якщо один операнд типу long, то другий операнд перетворюється до типу long;
  • 8) якщо один операнд типу unsigned int, то другий цілий операнд перетворюється до цього ж типу.

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

Приклад 4.4.

unsigned char c;

double f, d;

unsigned long n;

int i;

d = f * (i + c/n);

Порядок перетворення типів у прикладі 4.4:

  • 1) тип змінної c перетворюється до unsigned int (правило 5);
  • 2) тип змінної c перетворюється до unsigned long (правило 6);
  • 3) тип c/n перетворюється до unsigned long (правило 6);
  • 4) тип (i+c/n) перетворюється до unsigned long (правило 6);
  • 5) тип виразу перетворюється до double (правило 3);

Розглянемо ще кілька правил перетворення типів:

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

Приклад 4.5.

int m = 2, n = 3;

float a = m/n;       // результат: a=0

double k = 2.0;     

double rez = k/3;    // результат: rez=0.66(6)

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

Приклад 4.6.

float a = 2.8, b = 1.7;

int c = a * b;             // с=4, а не 4.76, бо с – ціле число

double x = 300, y = 200;

shоrt z = x * y;                // z=-5536, а не 60000, бо тип short <= 32767

При виконанні операцій перетворення типів може бути неявним, а при виконанні операції перетворення типів – явним.

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

(<тип>) <змінна або вираз>

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

Приклад 4.7. Явне перетворення типів.

int m = 2, n = 3;

double a = (double) m/n;              // результат: a=0.66(6)

int i = 5;

long j = 2;

double d = (double) i / (double) j;   // результат: d=2.5

Приклад 4.8.

int z, x;

double y = z/(x+25);

У цьому виразі змінні z та x є цілого типу, тому після обчислення виразу дробова частина втрачається. Щоб цього уникнути потрібно перетворити чисельник чи знаменник до дійсного типу одним із таких способів:

  • 1) дописати десяткову крапку до числа 25:

y = z/(x+25.);

  • 2) домножити чисельник або знаменник ліворуч на 1.0:

y = 1.0*z/(x+25);    // еквівалентно y = 1.*z/(x+25)

  • 3) явно вказати тип результату:

y = (double) z/(x+25);

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

Для отримання правильного результату при обчисленні арифметичних виразів потрібно дотримуватися таких правил:

  • кожний оператор (інструкція) повинен завершуватись крапкою з комою;
  • знаки множення пропускати не можна, наприклад, 3ab записують як 3*a*b;
  • якщо знаменник або чисельник містить операції +, -, *, /, то його слід записувати у круглих дужках;
  • записуючи раціональні дроби, у чисельнику чи знаменнику яких є числові константи, хоча б одну з них слід записувати з десятковою крапкою, наприклад, 2/k записують як 2.0/k чи 2./k;
  • радикали, тобто корінь кубічний і вище, заміняють дробовими степенями, наприклад, clip_image002.gifзаписують як pow(x+1, 1./3);
  • слід враховувати правила перетворення типів;
  • мова С чутлива до регістру;
  • аргумент функції завжди записують у круглих дужках.

1.4. Операції відношень та логічні операції

Операції відношень (<, >, <=, >=, ==, !=) використовуються для по­рівняння двох операндів. Результатом цих операцій для типу int є 0 або 1, а для типу boolfalse або true.

Логічна операціяце дія, яка виконується над логічними змінними, ре­зультатом якої є 0 (false) або 1 (true). Логічні операції обчислюють кожний операнд з огляду на його еквівалентність нулю.

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

Правила опрацювання логічних операцій:

1)     якщо перший операнд операції логічного додавання (||, операція “АБО”, диз’юнкція) має ненульове значення, то другий операнд не обчислюється;

2)     якщо значення першого операнда операції логічного множення (&&, операція “І”, кон’юнкція) дорівнює 0, то другий операнд не обчислюється;

3)     операція логічного заперечення (!, операція “НЕ”, інверсія) виконується над однією логічною змінною.

Логічні вирази будуються з логічних змінних, логічних операцій та дужок. Результати застосування логічних операцій до булевих значень подано у табл. 4.3.

                                                                                                                                  Таблиця 4.3.
                                                                    Логічні операції

A

B

!A

A || B

A&&B

0

0

1

0

0

0

1

1

1

0

1

0

0

1

0

1

1

0

1

1

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

Приклад 4.9. Виконати логічні операції

bool a, b, c = true, rez;

a = !c;              // результат: a=false

b = a;               // результат: b=false

b -= c;              // результат: b=true

rez = !(a < c);      // результат: rez=false

int z = 0, x, y, t=5, i;

x = !z;               // результат: x=1

y = (a==z)||(c&&a);  // результат: y=1

t -= c;               // результат: t=4

i = c-2;              // результат: i=-1

Крім звичайних логічний операцій, існують побітові логічні операції, які виконуються над цілими числами та опрацьову­ють число побітово. До цих операцій належать: побітове логічне заперечення “НЕ” (~), побітове логічне множення “І” (&), побітове логічне додавання “АБО” (|), побітове логічне виключне АБО (^), тобто побітове “АБО-НЕ” (табл. 4.4).

Операнди логічних операцій можуть бути будь-якого цілого типу.

                                                                                                                                  Таблиця 4.4.
                                                             Логічні побітові операції

A

B

~A

A | B

A&B

A^B

0

0

1

0

0

0

0

1

1

1

0

1

1

0

0

1

0

1

1

1

0

1

1

0

Приклад 4.10. Виконати логічні побітові операції

unsigned char a = 11, b = 202, r1, r2, r3, r4;

// у двійковій системі числення a = 00001011, b = 11001010

r1 = ~a         // ~00001011 = 11110100, результат r1=244

r2 = a & b      // 00001011 & 11001010 = 00001010, результат: r2=10

r3 = a | b      // 00001011 | 11001010 = 11001011, результат: r3=203

r4 = a ^ b      // 00001011 ^ 11001010 = 11000001, результат: r4=193

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

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

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

Приклад 4.11. Операції зсуву.

unsigned char a = 11, b = 202, r1, r2;    

// a = 00001011, b = 11001010

r1 = a << 3     // результат: 00001011<<3 = 01011000, тобто r1=11*23=88

r2 = b >> 4     // результат: 11001010>>4 = 00001100, тобто r2=202/24=12

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

Сумісні по типу константи, змінні та функції від них за допомогою знаків операцій та круглих дужок можуть об’єднуватися у вирази. Для формування виразів мова С має біля 40 різних операцій. Знаки операцій на мові С є контекстнозалежними, тобто один i той же символ може позначати різні операції. Операції можуть виконуватися тільки над однотипними або сумісними по типу операндами. Наступна схема демонструє наявні на мові С види операцій. Якщо у вираз входить більше однієї операції, то вони виконуються згідно правил пріоритетів (табл. 4.5):

1) виконуються операції у круглих дужках;

2) послідовність виконання операцій визначається спаданням рівня їх пріоритетів;

3) операції одного рівня пріоритетів виконуються у встановленому порядку, в основному зліва направо.

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

                                                                                                                                  Таблиця 4.5.
                                      Пріоритет і порядок виконання операцій за спаданням

з/п

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

Назва операції

Порядок

виконання

1

::

( )

[ ]

–>

.

Оператор розширення області дії

Вираз, виклик функцій

Виділення елемента масива

Виділення елемента структури або об’єднання

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

зліва направо

2

~

!

*

 

&

++

--

(<тип>)

sizeof

Унарний мінус (зміна знаку)

Порозрядна інверсія (побітове НЕ)

Логічне заперечення (НЕ)

Звертання за визначеною адресою (розіменування вказівника)

Отримання адреси (адресація)

Збільшення на одиницю (інкремент)

Зменшення на одиницю (декремент)

Явне перетворення типу

Визначення розміру в байтах

справа наліво

3

*

/

%

Множення

Ділення

Остача від ділення

зліва направо

4

+

Додавання

Віднімання

зліва направо

5

<< 

>> 

Арифметичний зсув вліво

Арифметичний зсув вправо

зліва направо

6

<=

>=

Менше

Більше

Менше або дорівнює

Більше або дорівнює

зліва направо

7

==

!=

Дорівнює

Не дорівнює

зліва направо

8

&

Порозрядне логічне множення (I)

зліва направо

9

^

Порозрядна сума за модулем два

зліва направо

10

|

Порозрядне логічне додавання (АБО)

зліва направо

11

&&

Логічне множення (I)

зліва направо

12

||

Логічне додавання (АБО)

зліва направо

13

?:

Умовна тернарна операція

справа наліво

14

=

*=

/=

%=

+=

– =

&=

|=

^=

 

>>=

<<=

Присвоєння

Присвоєння з множенням

Присвоєння з діленням

Присвоєння остачі від ділення цілих чисел

Присвоєння з додаванням

Присвоєння з відніманням

Присвоєння з порозрядною операцією (І)

Присвоєння з порозрядною операцією (АБО)

Присвоєння з порозрядною операцією виключне (АБО-НЕ)

Присвоєння зі зсувом вправо

Присвоєння зі зсувом вліво

справа наліво

15

,

Кома

зліва направо

Приклад 4.12. Визначити пріоритети операцій та обчислити вираз clip_image004.gif.

#include <stdio.h>

#include <conio.h>

void main() {

       char a=17;

       long b=16;

       unsigned d=14;

       int e=-20;

       // one step

printf("Vyraz = %ld\n", ~sizeof(char)==!a&&b++^(++d*!e));

       // return previous values

       b=16;

       d=14;

       // step by step

       long k1,k2,k3,k4,k5,k6,k7,k8,k9,k10;

       k1 = !e;

       k2 = ++d;

       k3 = k1 * k2;

       k4 = !a;

       k5 = sizeof(char);

       k6 = ~k5;

       k7 = k6 == k4;

       k8 = b ^ k3;

       k9 = k7 && k8;

       k10 = b++;

       printf("Vyraz = %ld\n", k9);

       getch();

}

1.5. Математичні функції

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

#include <ім’я файлу>

Так, для можливості виклику математичних функцій необхідно записати

#include <math.h>

Для запису різних математичних залежностей та виразів мова програмування С надає змогу використовувати вбудовані математичні функції. Вони підключаються за допомогою бібліотеки math.h. Список вбудованих математичних функцій С/С++ подано у табл. 4.6.


(Для ознайомлення з повним текстом статті необхідно залогінитись)