- •12. Класи пам'яті даних 100
- •13. Робота з файлами 106
- •14. Посилання 111
- •Склад мови
- •Алфавіт мови
- •Лексеми
- •Ключові слова
- •Ідентифікатори
- •Константи
- •Символьні рядки
- •Знаки операцій, роздільники, коментарі
- •Типи даних
- •Класифікація типів даних
- •Цілочислові типи
- •Дійсні типи
- •Оголошення змінних і констант
- •Переліки
- •Структура програми
- •Функція main
- •Область дії змінної
- •Введення і виведення даних
- •Функції стандартної математичної бібліотеки
- •Вирази і операції
- •Поняття виразу, операнда, операції
- •Порядок виконання операцій
- •Арифметичні операції
- •Порозрядні операції
- •Операції порівняння
- •Логічні операції
- •Операції присвоєння
- •Умовна операція
- •Операція визначення розміру sizeof
- •Узгодження типів у виразах
- •Умовні оператори
- •Оператори
- •Умовний оператор if
- •Оператор вибору switch
- •Оператори циклу
- •Цикл з параметром. Оператор for
- •Цикл з передумовою. Оператор while
- •Цикл з постумовою. Оператор do while
- •Оператори переходу
- •Використання псевдовипадкових чисел
- •Одновимірні масиви
- •Багатовимірні масиви
- •Символьні рядки
- •Вказівники
- •Оголошення вказівника, операції, пов’язані з вказівниками
- •Адресна арифметика
- •Void – вказівники, типізація вказівників
- •Звертання до елементів масивів через вказівники
- •Масиви символьних рядків і масиви вказівників
- •Динамічне виділення пам’яті
- •Структури і об’єднання
- •Оголошення і ініціалізація структур
- •Звертання до елементів структур
- •Перейменування типів
- •Об’єднання
- •Поля бітів
- •Директиви препроцесора
- •Призначення директив препроцесора
- •Директива включення #include
- •Директиви макропідстановок #define I #undef
- •Директиви умовної компіляції
- •Директиви #ifdef, #ifndef
- •Функції
- •Структура функції
- •Виклик функцій. Прототипи функцій
- •Взаємодія фактичних і формальних параметрів функцій
- •Inline – функції
- •Масиви і символьні рядки як параметри функцій
- •Використання кваліфікатора const в оголошеннях параметрів
- •Багатовимірні масиви як параметри функцій
- •Опрацювання структур у функціях
- •Вказівники на функції
- •Рекурсивні функції
- •Класи пам'яті даних
- •Клас пам'яті, час існування і видимість об’єкта
- •Область дії глобальних і локальних змінних
- •Специфікатори класів пам'яті
- •Специфікатори глобальних змінних
- •Багатофайлові програми
- •Робота з файлами
- •Звертання до файлів
- •Послідовний запис до файлу і послідовне читання з файлу
- •Файли з довільним доступом
- •Посилання
- •Призначення посилань
- •Передача аргументів функцій як посилань
Операції порівняння
Операції порівняння (ще їх називають операціями відношення) є бінарними. Результатом виконання операцій є величина логічного типу – true або false. До операцій порівняння відносять:
> більше;
>= не менше;
< менше;
<= не більше;
== дорівнює;
!= не дорівнює.
Поширеною помилкою є використання знаку присвоєння = замість знака рівності ==. Оскільки присвоєння це також операція, що повертає присвоєне значення, компілятор може не фіксувати помилку в таких виразах, але часто видає попередження.
Логічні операції
В мові програмування С++ застосовуються три логічні операції:
! логічне заперечення, унарна операція;
&& логічне І, бінарна операція;
|| логічне АБО, бінарна операція.
Операндами логічних операцій є логічні дані – істина (true) і хибність (false). Результатом логічної операції є величина логічного типу. Операндами також можуть бути числові дані: будь яке не нульове значення – це істина, нуль – хибність. Цей підхід використовується в мові програмування С, в якій немає логічного типу даних bool.
Операція логічного заперечення змінює логічне значення на протилежне. Тобто,
#include <iostream>
using namespace std;
int main(){
bool a = true;
cout << a << endl; // 1
cout << !a << endl; // 0
}
Результат бінарної операції && буде істинним (не буде дорівнювати нулю), тільки в тому разі, коли обидва операнди є істинними (не дорівнюють нулю). Результат виконання операції || буде істинним, коли істинним є хоча б один з операндів.
Логічні вирази в С++ не обов’язково мають бути обчислені повністю. Як тільки значення виразу стає однозначним, подальші обчислення припиняються. При цьому, лівий операнд логічної операції обчислюється першим, а правий – другим. Це дає можливість записувати вирази, в яких одразу виконується зміна даних і перевірка. В деяких випадках це може призводити до некоректної роботи програми. Наприклад:
1 #include <iostream>
2 using namespace std;
3 int main(){
4 int a1 = 0, b1 = 1, c1 = 2;
5 int a2 = 0, b2 = 1, c2 = 2;
6 bool r;
7 r = b1 < c1 && ++a1 > 0; // r = true
8 cout << "a1 = " << a1 << endl; // a = 1
9 r = b2 > c2 && ++a2 > 0; // r = false
10 cout << "a2 = " << a2 << endl; // a = 0
11 }
В програмі обчислення значення змінної r виконується в рядках 7 і 9. В обох випадках використовують логічну операцію І. При виконанні операції І першим буде обчислене значення лівого операнда. Якщо це false, то незалежно від значення правого операнда результат виконання операції буде false, і вираз справа від знака операції І обчислений не буде. В прикладі в рядку 7 обчислюються вирази і зліва, і заправа від знака операції І, в рядку 9 – лише зліва. Таким чином, незважаючи на те, що пріоритет операції префіксного інкременту більший пріоритетів логічних операцій і операцій порівняння, в рядку 9 змінна а не буде збільшена на одиницю.
Операції присвоєння
Операції присвоєння можна поділити на 2 групи:
унарні операції:
++ (постфіксний і префіксний інкремент, збільшення на одиницю),
-- (постфіксний і префіксний інкремент, зменшення на одиницю);
бінарні операції:
= (звичайне присвоєння),
*= (множення з присвоєнням),
/= (ділення з присвоєнням),
%= (остача від ділення з присвоєнням),
+= (додавання з присвоєнням),
-= (віднімання з присвоєнням),
&= (побітове І з присвоєнням),
^= (побітове виключне І з присвоєнням),
|= (побітове АБО з присвоєнням),
<<= (зсування вліво з присвоєнням),
>>= (зсування вправо з присвоєнням).
На відміну від інших операцій, операції присвоєння змінюють значення свого операнда: для бінарних операцій лівий операнд набуває значення виразу, записаного справа від знака присвоєння, для унарних операцій – змінюється значення єдиного операнда даної операції. Тому операнд, якому присвоюється значення, повинен бути так званим l-операндом (l-value, left side value) – змінною розадресованим вказівником, тобто він має задавати адресу оперативної пам'яті, куди буде записане значення, яке присвоюється.
Результатом операції присвоєння є значення, яке набуває змінна (l-операнд) після присвоєння. Це значення можна використовувати як операнд у наступних операціях, для яких присвоєння є підвиразом. Операції присвоювання виконуються справа наліво, що дозволяє записати вираз, який складається з декількох присвоєнь (рядок 5 і 7).
1 #include <iostream>
2 using namespace std;
3 int main(){
4 int a, b, c;
5 a = b = c = 123;
6 cout << a << endl; // 123
7 a = b = c + 321;
8 cout << a << endl; // 444
9 }
Бінарні присвоєння стоять у кінці списку пріоритетів, тому іноді підвираз присвоювання слід охоплювати дужками:
#include <iostream>
using namespace std;
int main(){
int a, b = 1, c = 2;
bool r;
r = a = b + c < 2; // 0, a = 3 < 0, a = 0
cout << a << endl;
r = (a = b + c) < 2; // 3
cout << a << endl;
}
Комбіновані присвоєння є окремим випадком звичайних присвоювань. Вираз
операнд1 операція= операнд2;
є скороченим записом операції присвоєння:
операнд1 = операнд1 операція операнд2;
Операція виключне АБО має таку особливість: (a ^ b) ^ b = a. Тобто, якщо виконати операцію 2 рази з однаковим другим операндом, ми отримаємо значення першого операнда. Це дозволяє виконувати обмін двох цілочислових змінних значеннями.
#include <iostream>
using namespace std;
int main(){
int a = 123, b = 321;
a ^= b ^= a ^= b;
cout << "a = " << a << endl; // 321
cout << "b = " << b << endl; // 123
}
В програмах на С++ широко застосовують унарні операції присвоєння ++ і --. Перша з них називається інкрементом, вона збільшує значення операнда на одиницю. Друга – декрементом, зменшує значення операнда на одиницю. Можна застосовувати дві форми запису операцій інкремента і декремента: префіксну, коли знак ++/-- записується перед операндом, і постфіксну – коли знак операції вказується після операнда.
Якщо унарне присвоєння використовується як окремий оператор, то обидві форми запису – префіксна і постфіксна – рівнозначні. В наступному прикладі наведені чотири альтернативні способи збільшення і зменшення значення змінної на одиницю.
#include <iostream>
using namespace std;
int main(){
int a = 0, b = 0;
a++; ++a; a += 1; a = a + 1; // Збільшення на 1
b--; --b; b -= 1; b = b - 1; // Зменшення на 1
cout << "a = " << a << endl;
cout << "b = " << b << endl;
}
Різниця між постфіксною і префіксною формами запису проявляється, коли операції інкремента і декремента входять до складу іншого виразу. Префіксний інкремент (декремент) встановлює, що спочатку значення змінної збільшується (зменшується) на одиницю, і після цього нове значення змінної вступає в іншу операцію. Якщо використовується постфіксна форма, то спочатку значення змінної використовується у виразі, потім збільшується (зменшується) на одиниці.
#include <iostream>
using namespace std;
int main(){
int a = 3, b = 3, ta, tb;
ta = ++a + 1;
tb = b++ + 1;
cout << "ta = " << ta << endl; // 5
cout << "tb = " << tb << endl; // 4
}
