Мова програмування С++
Дипломна робота
Мова програмування С++
Зміст
1. Створення простих програм на С++
1.1 Структура програми
1.2 Етапи виконання програми
1.3 Порядок запуску програми
2. Форматний ввід/вивід у мові С/С++
2.1 Функції вводу/виводу мови С
2.2 Функції вводу/виводу та маніпулятори мови С++
3. Лінійні програми на С++
3.1 Стандартні типи даних мови С++
3.2. Операції мови С++
4. Основні оператори мови С++
4.1 Складові оператори
4.2 Оператори розгалуження
4.3 Оператори циклу
4.4 Оператори переходу
5. Вказівними та операції над ними
5.1 Поняття вказівника
5.2 Дії над вказівниками
6. Робота з одновимірними масивами
6.1 Статичні та динамічні масиви
6.2 Рядки, як одновимірні масиви
7. Двовимірні масиви
8. Символьна інформація та рядки
8.1 Збереження символьної інформації
8.2 Функції вводу/виводу для роботи з рядками
8.3 Спеціальні функції для роботи з рядками та символами
9. Функції користувача
9.1 Функції: визначення, опис, виклик
9.2 Передача масивів у функцію
9.3 Перевантаження функцій у С++
9.4 Функції зі змінною кількістю параметрів
10. Структури
Список літератури
1. Створення простих програм на С++
C++ (Сі-плюс-плюс) — універсальна мова програмування високого рівня з підтримкою декількох парадигм програмування: об'єктно-орієнтованої, узагальненої та процедурної. Розроблена Б'ярном Страуструпом (англ. Bjarne Stroustrup) в AT&T Bell Laboratories (Мюррей-Хілл, Нью-Джерсі) у 1979 році та названа «Сі з класами». Страуструп перейменував мову у C++ у 1983 р. Базується на мові Сі. Визначена стандартом ISO/IEC 14882:2003.
1.1 СТРУКТУРА ПРОГРАМИ
Розглянемо програму, що виводить на екран монітора фразу “Ласкаво просимо до С++!”:
Приклад 1.
// Welcome.cpp – ім’я файла з програмою
# include <iostream.h>
void main ()
{ cout << ” Ласкаво просимо до С++! \ n”;
}
Результат виконання програми:
Ласкаво просимо до С++!
У першому рядку програми міститься однорядковий коментар, що починається з символу “//”, який вказує, що після цього символу йде однорядковий коментар. Коментарі не викликають ніяких дій комп’ютера і ігноруються компілятором С++, а лише допомагають іншим людям читати і зрозуміти Вашу програму.
У другому рядку розміщено команду (директиву) препроцесору, що забезпечує включення до програми засобів зв’язку зі стандартними потоками вводу і виводу даних. Вказані засоби містяться у файлі під назвою iostream.h (мнемоніка: “і” (input) – ввід; “output” – вивід; “stream” – потік; “head” - заголовний). Рядок, що починається з ”#”, обробляється препроцесором перед компіляцією програми. Файл iostream.h повинен бути залучений для всіх програм, що виводять дані на екран монітора або вводять дані з клавіатури.
Третій рядок є заголовком функції з іменем main. Будь-яка програма на С++ повинна містити лише одну функцію з таким іменем. Саме з неї починається виконання програми. void – специфікатор типу, який вказує, що функція main в даному прикладі не повертає ніякого значення. Круглі дужки після main потрібні в зв’язку з форматом (синтаксисом) заголовка будь-якої функції. В них розміщується список параметрів. У нашому прикладі параметри не потрібні.
Тіло будь-якої функції повинно починатися і закінчуватися фігурними дужками, між якими знаходиться послідовність описів, операторів і визначень. Кожен оператор, визначення чи опис повинні закінчуватися крапкою з комою.
Рядок
cout << ” Ласкаво просимо до С++! \ n”;
є командою комп’ютеру надрукувати на екрані рядок символів, що записаний у лапках. Повний рядок, включаючи cout, операцію ”<<”, рядок ”Ласкаво просимо до С++! \ n” і крапку з комою “;”, називається оператором. Всі вводи і виводи в С++ виконуються над потоками символів. Таким чином потік символів Ласкаво просимо до С++! спрямовується до об’єкта стандартного потоку виводу cout, який пов’язаний з екраном. Вже зараз слід відмітити одну з принципових особливостей мови С++, яку називають перевантаженням або розширенням дії стандартних операцій. Операція ”<<” називається операцією „розмістити у потік” лишень у тому випадку, коли зліва від неї знаходиться ім’я об’єкта cout. Інакше пара символів “<<” означає бінарну операцію зсуву вліво. Символи правого операнда зазвичай виводяться так само, як вони виглядають між лапками.
Слід зазначити, що символи ”\n” не виводяться на екран. Комбінацію символів, що починаються з позначки оберненого Стеша (”\”), називають знаком переходу або escape-символом. Керуюча послідовність ”\n” означає перехід на початок нового рядка. Цей символ в лапках може знаходитися будь-де в рядку, при цьому послідовність символів, що знаходиться за ним, виводитиметься з нового рядка. Тобто результат виконання операції
cout << ” Ласкаво просимо \nдо С++! \ n”;
матиме вигляд:
Ласкаво просимо
до С++!
1.2 ЕТАПИ ВИКОНАННЯ ПРОГРАМИ
Вихідна програма, підготовлена на мові С++ у вигляді текстового файла з розширенням *.срр (welcome.cpp), проходить 3 етапи обробки:
препроцесорне перетворення тексту програми;
компіляція;
компоновка (редагування звязків чи складання).
Після цих 3 етапів формується машинний код програми, що виконується.
Задачею препроцесора є перетворення (доповнення) тексту програми до початку її компіляції. Правила препроцесорної обробки визначаються програмістом за допомогою директив препроцесора. Директива починається з ”#” (дієс, шарп). Наприклад,
1) #define - визначає правила заміни в тексті:
#define ZERO 0.0
Це означає, що кожне використання у програмі імені ZERO буде замінюватися на 0.0.
2) #include< імя заголовного файла > - передбачена для залучення до тексту програми тексту файлу з каталогу “Заголовних файлів” INCLUDE, які постачаються разом зі стандартними бібліотеками. Кожна бібліотечна функція чи обєкт С++ має відповідний опис в одному з заголовних файлів (наприклад, iostream.h, stdio.h, conio.h, math.h). Список заголовних файлів визначається стандартом мови. Використання директиви include не підєднує відповідну стандартну бібліотеку, а лише дозволяє долучити до тексту програми описи із зазначеного заголовного файлу. В нашому випадку препроцесор обробляє директиву #include <iostream.h> і під’єднує до вихідного тексту програми засоби для обміну з дисплеєм. Далі файл передається на компіляцію, у ньому виявляються синтаксичні помилки, які потрібно усунути програмістові. Після безпомилкової компіляції текст програми перекладається компілятором на машинну мову, далі отримуємо об’єктний файл з розширенням *.obj. Підключення обєктних кодів файлів з визначеннями необхідних стандартних функцій і обєктів з бібліотеки відбувається на етапі компоновки, тобто після компіляції. У обєктному коді створюваної програми ніби замуровуються дірки за допомогою кодів стандартних функцій. Хоча в заголовних файлах містяться всі описи стандартних функцій, до коду програми залучаються лише функції й обєкти, які використовуються в програмі.
Після компоновки утворюється модуль програми з розширенням *.ехе.
Отже, в нашому випадку, виконавши директиви, препроцесор сформує повний текст програми, компілятор створить об’єктний файл welcome.obj, за замовчуванням обравши для нього зазначене ім’я, а компоновщик (редактор зв’язків Linker) доповить програму бібліотечними функціями, наприклад, для роботи з об’єктом cout і побудує модуль welcome.exe, запустивши, який ми одержуємо на екрані бажану фразу. Схема етапів виконання програми наведена на рис. 1.1.
1.3 ПОРЯДОК ЗАПУСКУ ПРОГРАМИ
Відкрийте нове вікно редагування (File > New) і надайте йому ім’я Welcome (File > Save As);
У новому вікні наберіть текст програми, що наводиться у Прикладі 1.
Відкомпілюйте програму (Compile > Compile або (Alt+F9)). В разі повідомлень про помилку, перевірте текст програми і усуньте невідповідності. Щоразу, вносячи зміни у вихідний текст програми, зберігайте файл (File > Save або F2). Після чого змінену програму слід відкомпілювати;
Запуск відкомпільованої програми здійснюється за командою (Run > Run або Ctrl+F9). Якщо з моменту останньої компіляції вихідний код було модифіковано, ця команда виконає послідовно компіляцію і компоновку. Результат виконання програми можна переглянути, натиснувши комбінацію клавіш Alt+F5.
2. Форматний ввід/вивід у мові С/С++
2.1 ФУНКЦІЇ ВВОДУ/ВИВОДУ МОВИ С
У мові С++ немає вбудованих засобів вводу/виводу – вони здійснюються за допомогою функцій, типів та об’єктів, що містяться у стандартних бібліотеках. Використовується два способи: функції, успадковані з мови С та об’єкти С++.
Основні функції вводу/виводу в стилі С, опис яких міститься у заголовному файлі <stdio.h>:
рrintf (<керуючий рядок>, <список аргументів>);
Керуючий рядок береться у лапки і вказує компілятору вигляд інформації, що виводиться. Вона може містити специфікації перетворення і керуючи або escape-символи.
Специфікація перетворення має такий вигляд:
% <прапор> <розмір поля . точність> специфікація,
де прапор може набувати наступних значень:
- вирівнювання вліво числа, що виводиться (за замовчуванням виконується вирівнювання вправо);
+ виводиться знак додатного числа;
розмір поля – задає мінімальну ширину поля, тобто довжину числа. Якщо ширини поля недостатня, автоматично виконується його розширення;
точність – задає точність числа, тобто кількість цифр його дробової частини;
специфікація вказує на вигляд інформації, що виводиться. У таблиці 2.1 наведено основні формати функції друку.
Таблиця 2.1
Формат |
Тип інформації, що виводиться |
%d |
десяткове ціле число |
% і |
для виведення цілих чисел зі знаком (printf (“a=%i”, -3)); |
%u |
для виводу беззнакових цілих чисел (printf(“s=%u”, s)) |
%c |
один символ |
%s |
рядок символів |
%e |
число з плаваючою крапкою (експоненційний запис) |
%f |
число з плаваючою крапкою (десятковий запис) (printf(“b=%f\n, c=%f\n, d=%f\n”, 3.55, 82.2, 0.555 )); |
%u |
десяткове число без знака |
Керуючий рядок може містити наступні керуючі символи:
\n – перехід на новий рядок;
\t – горизонтальна і \v – вертикальна табуляція;
\b – повернення назад на один символ;
\r – повернення на початок рядка;
\a – звуковий сигнал;
\” –лапки;
\? – знак питання;
\\ - зворотний слеш.
Список аргументів - обєкти, що друкуються (константи, змінні). Кількість аргументів та їх типи повинні відповідати специфікаціям перетворення в керуючому рядку.
Приклад 1.
#include <stdio.h>
#define PI 3.1415926
void main()
{
int number=5, cost=11000, s=-777;
float bat=255, x=12.345;
printf ("%d студентів зїло %f бутербродів.\n", number, bat);
printf ("Значення числа pi рівне%f.\n", pi);
printf ("Вартість цієї машини %d%s\n", cost,"у.е");
printf ("x=%-8.4f s=%5d%8.2f ", x, s, x);
}
В результаті виконання останньої функції printf() на екрані буде виведено:
х=12.3450 s= -777 12.34
Функція scanf передбачена для форматного вводу інформації довільного вигляду. Загальний вигляд функції:
scanf (<керуючий рядок>, < список адрес>);
На відміну від функції виводу printf(), scanf() використовує у списку адреси змінних, для одержання яких перед іменем змінної ставиться символ ”&”, що позначає унарну операцію одержання адреси. Для вводу значень рядкових змінних символ ”&” не використовується. При використанні формату %s рядок вводиться до першого пропуску. Вводити дані можна як в одному рядку через пропуск, так і в різних рядках.
Дану особливість ілюструє відповідна частина програми:
int course;
float grant;
char name[20];
printf ( "Вкажіть ваш курс, стипендію, імя \n");
scanf ( "%d%f", &course, &grant);
scanf ( "%s", name); /* ”&” відсутній при зазначенні масиву символів */
Для зміни кольору тексту використовують функції із файла <conio.h>: clrscr() – очищує екран; textcolor(Колір) – задає колір символів; textbackground (Колір) – встановлює колір фону. Вивід тексту на екран здійснюється за допомогою функції cprintf(), яка використовується аналогічно printf(). Зверніть увагу на те, що перехід на початок нового рядка у цій функції здійснюється за допомогою комбінації ”\n\r”.
Колір можна задати за допомогою цілої або іменованої константи, перелік яких наводиться у таблиці 2.2.
Таблиця 2.2
-
Колір
Константа
Значення константи
Чорний
BLACK
0
Синій
BLUE
1
Зелений
GREEN
2
Червоний
RED
4
Фіолетовий
MAGENTA
5
Сірий
GREY
8
Блакитний
LIGHTBLUE
9
Помаранчевий
LIGHTRED
12
Жовтий
YELLOW
14
Білий
WHITE
15
2.2 ФУНКЦІЇ ВВОДУ/ВИВОДУ ТА МАНІПУЛЯТОРИ МОВИ С++
А ось як виглядає програма вводу/виводу з використанням бібліотеки класів С++:
Приклад 2.
# include <iostream.h>
void main()
{ int i;
cout<< “Введіть ціле число\n”;
//об’єкт для вводу з клавіатури і >>розміщення у потік виводу
cin>> i;
cout<< “Ви ввели число”<< i <<”дякую!”;
}
Для форматного виводу у С++ використовуються маніпулятори, для використання яких до програми потрібно підключити заголовний файл <iomanip.h>:
setw(int) – встановлює максимальну ширину поля виводу чисел та рядків (не символів);
setprecision(int) – встановлює максимальну кількість цифр дробової частини для дійсних чисел з фіксованою крапкою;
setiosflags(ios::showpoint | ios::fixed) – вивід дійсних чисел з фіксованою крапкою;
setiosflags(ios::left) або setiosflags(ios::right) – вирівнювання по лівому або правому полю;
endl – при виводі включає у потік символ нового рядка, еквівалентний “\n” (його опис міститься у файлі iostream.h).
Маніпулятори спрямовуються в потік виводу, аналогічно тому, як це зроблено у прикладі 3:
Приклад 3.
# include<iostream.h>
#include <iomanip.h>
void main()
{float d=52.28679;
float f= 410.0;
cout<< setprecision(3);
cout<<setiosflags(ios::showpoint | ios::fixed);
cout<<setw(12)<<d<<endl<<setw(12)<<f<<endl;
}
Результат виводу ( позначає пробіл):
52.287
410.000
У даному прикладі маніпулятори точності та фіксації крапки спрямовуються у потік виводу одноразово, тоді як ширину поля виводу необхідно встановлювати для кожного значення.
3. Лінійні програми на С++
3.1 СТАНДАРТНІ ТИПИ ДАНИХ МОВИ С++
Всі обєкти (змінні, масиви тощо), з якими працює програма в С/С++, необхідно визначати або описувати. Найпростіша форма визначення змінної:
<тип> <список імен змінних>;
При оголошенні обєкти можна ініціалізувати (задавати початкове значення).
Наприклад: int j=10, m(3), n;
float c(-1.3), l=-10.23, f1;
Оголошення повідомляють компілятору про властивості та імена обєктів і функцій. Змінні можуть змінювати свої значення. При наданні значення змінній у комірці памяті, яка відводиться під неї, розміщується код цього значення. Доступ до значення цієї змінної можливий через імя змінної, а доступ до ділянки памяті здійснюється за її адресою. Розмір ділянки памяті, що відводиться змінній, визначається її типом. Перелік базових типів даних наведено у таблиці 3.1.
Таблиця 3.1
Тип даних |
Назва |
Розмір, біт |
Діапазон значень |
unsigned char |
Беззнаковий цілий довжиною не менше 8 біт |
8 |
0 . . 255 |
сhar |
Цілий довжиною не менше 8 біт |
8 |
-128 . . 127 |
unsigned int |
Без знаковий цілий |
16 |
0 . . 65535 |
short int (short) |
Короткий цілий |
16 |
-32768 . . 32767 |
unsigned short |
Беззнаковий короткий цілий |
16 |
0 . . 65535 |
int |
Цілий |
16 |
-32768 . . 32767 |
unsigned long |
Беззнаковий довгий цілий |
32 |
0 . . 4294967295 |
long int (long) |
Довгий цілий |
32 |
-214748348 . . 2147483647 |
float |
Дійсний одинарної точності |
32 |
3.4Е-38 . . 3.4Е+38 |
double |
Дійсний подвійної точності |
64 |
1.7Е-308 . . 1.7Е+308 |
long double |
Дійсний максимальної точності |
80 |
3.4Е-4932 . . 1.1Е+4932 |
3.2 ОПЕРАЦІЇ МОВИ С++
Позначки операцій – це один або декілька символів, що визначають дію над операндами. Операції поділяють на унарні, бінарні та тернарні за кількістю операндів, які беруть участь в операції (таблиця 3.2).
Таблиця 3.2.
Операція |
Короткий опис |
Унарні операції |
|
& |
Операція одержання адреси операнда |
* |
Звернення за адресою (розіменування) |
- |
Унарний мінус – змінює знак арифметичного операнда |
~ |
Порозрядове інвертування внутрішнього двійкового коду (побітове заперечення) |
! |
Логічне заперечення (НЕ) значення операнда. Цілочисельний результат 0 (якщо операнд ненульовий, тобто істинний) або 1 (якщо операнд нульовий, тобто хибний). Таким чином: !1 дорівнює 0; !2 дорівнює 0; !(-5)=0; !0 дорівнює 1. |
++ |
Інкремент (збільшення на одиницю): Префіксна операція (++х) збільшує операнд на 1 до його використання. Постфіксна операція (х++) збільшує операнд на 1 після його використання. int m=1, n=2; int a=(m++)+n; // a=3, m=2, n=2 int b=m+(++n);// b=6, m=2, n=3 |
- - |
Декремент (зменшення на одиницю): Префіксна операція (--х) зменшує операнд на 1 до його використання. Постфіксна операція (х--) зменшує операнд на 1 після його використання. |
sizeof |
Обчислення розміру (в байтах) обєкта того типу, який має операнд. Має дві форми: 1) sizeof (вираз); sizeof(1.0); // Результат - 8, Дійсні константи за замовчуванням мають тип double; 2) sizeof (тип) sizeof (char); // Результат – 1. |
Бінарні операції |
|
Арифметичні операції |
|
+ |
Бінарний плюс (додавання арифметичних операндів) |
- |
Бінарний мінус (віднімання арифметичних операндів) |
Мультиплікативні |
|
* |
Добуток операндів арифметичного типу |
/ |
Ділення операндів арифметичного типу (якщо операнди цілочисельні, абсолютне значення результату заокруглюється до цілого, тобто 20/3 дорівнює 6) |
% |
Одержання залишку від ділення целочисельних операндів (13%4 = 1) |
Операції зсуву (визначені лише для цілочисельних операндів) |
|
<< |
Зсув вліво бітового представлення значення лівого цілочисельного операнда на кількість розрядів, рівну значенню правого операнда (4<<2 дорівнює 16, т.я. код 4 100, а звільнені розряду обнуляються, 10000 – код 16) |
>> |
Зсув вправо бітового представлення значення правого цілочисельного операнда на кількість розрядів, рівну значенню правого операнда |
Порозрядні операції |
|
& |
Порозрядна кон’юнкція (І) бітових представлень значень цілочисельних операндів |
| |
Порозрядна диз’юнкція (АБО) бітових представлень значень цілочисельних операндів |
^ |
Порозрядне виключне АБО бітових представлень значень цілочисельних операндів |
Операції порівняння |
|
< |
Менше, ніж |
> |
Більше, ніж |
<= |
Менше або рівне |
>= |
Більше або рівне |
= = |
Рівне |
!= |
Не рівне |
Логічні бінарні операції |
|
&& |
Кон’юнкція (І) цілочисельних операндів або відношень, цілочисельний результат (0) або (1) |
|| |
Диз’юнкція (АБО) цілочисельних операндів або відношень, цілочисельний результат (0) або (1) (умова 0<x<1 мовою С++ записується як 0<x && x<1) |
Тернарна операція |
|
Умовна операція |
|
? : |
Вираз1 ? Вираз2 : Вираз3; Першим вираховується значення Виразу1. Якщо воно істинне, тоді обчислюється значення Виразу2, яке стає результатом. Якщо при обчисленні Виразу1 одержуємо 0, тоді в якості результату береться значення Виразу3. Наприклад: х<0 ? -x : x ; //обчислюється абсолютна величина x. |
Таблиця 3.3. Пріоритет виконання операцій
-
Ранг
Операції
Напрямок виконання
1
() (виклик функції), [], ->, "."
>>>
2
!, ~, +, - (унарні), ++, --, *, (тип), sizeof, (new,delete – Сі++)
<<<
3
.* , ->* - Сі++
>>>
4
*, /, % (бінарні)
>>>
5
+, - (бінарні)
>>>
6
<<, >>
>>>
7
<, <=, =>, >
>>>
8
==, !=
>>>
9
& (порозрядна)
>>>
10
^
>>>
11
| (порозрядна)
>>>
12
&& (логічна)
>>>
13
|| (логічна)
>>>
14
?: (тернарна)
<<<
15
=, +=, -=, *=, /=, %=, &=, ^=, |=, <<=,>>=
<<<
16
"," (кома)
>>>
Основні матичні функції мови С/С++, опис яких міститься у файлі <math.h>, наведені у таблиці 3.4.
Таблиця 3.4
Матичний запис |
Функція |
Пояснення |
Приклад |
arccos x |
acos |
Повертає арккосинус кута, рівного х радіан |
acos(x); |
arcsin x |
asin |
Повертає арксинус аргументу х в радіанах |
asin(x); |
arctg x |
atan |
Повертає арктангенс аргументу х в радіанах |
atan(x); |
аrctg(x/у) |
atan2 |
Повертає арктангенс відношення параметрів х та у в радіанах |
atan2(x, y); |
- |
ceil |
Заокруглює дійсне значення х до найближчого більшого цілого і повертає його як дійсне |
ceil(x); |
cosx |
cos |
Повертає косинус кута, рівного х радіан |
cos(x); |
chx=1/2(ex+e-x) |
cosh |
Повертає гіперболічний косинус аргументу, рівного х радіан |
cosh(x); |
ex |
exp |
Повертає результат піднесення числа е до степені х |
exp(x); |
|x| |
fabs |
Повертає модуль дійсного числа х |
fabs(x); |
- |
floor |
Заокруглює дійсне число до найближчого меншого числа і повертає результат як дійсний |
floor(x); |
- |
fmod |
Повертає залишок ділення х на у. Аналогічна операції %, але працює з дійсними числами |
fmod(x, y); |
ln x |
log |
Повертає значення натурального логарифму х |
log(x); |
lg x |
log10 |
Повертає значення десяткового логарифму х |
log10(x); |
xy |
pow |
Вираховує значення числа х у степені у |
pow(x, y); |
sinx |
sin |
Повертає синус кута, рівного х радіан |
sin(x); |
sh x=1/2 (ex-e-x) |
sinh |
Повертає гіперболічний синус кута, рівного х радіан |
sinh(x); |
|
sqrt |
Визначає корінь квадратний числа х |
sqrt(x); |
tg x |
tan |
Повертає тангенс кута, рівного х радіан |
tan(x); |
tgh x |
tanh |
Повертає гіперболічний тангенс кута, рівного х радіан |
tanh(x); |
Таблиця 3.5 Операції присвоювання
Операція |
Пояснення |
Приклад |
= |
Присвоїти значення виразу-операнду з правої частини операнду лівої частини |
Р=10.5-3*х |
*= |
Присвоїти операнду лівої частини добуток значень обох операндів |
Р*=2 еквівалентно Р=Р*2 |
/= |
Присвоїти операнду лівої частини результат від ділення значення лівого операнда на значення правого |
Р/=(2.2-х) еквівалентно Р=Р/(2.2-х) |
%= |
Присвоїти лівому операнду залишок від ділення цілочисельного значення лівого операнда на цілочисельне значення правого операнда |
Р%=3 еквівалентно Р=Р%3 |
+= |
Присвоїти операнду лівої частини суму значень обох операндів |
А+=В еквівалентно А=А+В |
-= |
Присвоїти операнду лівої частини різницю значень лівого і правого операндів |
Х-=3.4-у еквівалентно Х=Х-(3.4-у) |
4. Основні оператори мови С++
4.1 СКЛАДОВІ ОПЕРАТОРИ
Складовий оператор – це два або більше оператори, що повинні виконуватися у певній частині програми як один оператор. До складових операторів належать власне складовий оператор та блок. В обох випадках - це послідовність операторів, розміщених у фігурних дужках. Блок відрізняється від складового оператора наявністю в його тілі оператора визначення об’єкту (змінної, константи, масиву тощо).
Наприклад:
{n++; summa+=n;}//це складовий оператор
{int n=0; n++;summa+=n;} //це блок
4.2 ОПЕРАТОРИ РОЗГАЛУЖЕННЯ
Оператор умовного переходу if використовується для спрямування ходу програми за однією з гілок обчислень в залежності від певної умови.
Загальна форма запису:
if (умова) оператор1;
else оператор2;
Наприклад, для знаходження коренів квадратного рівняння використовується запис:
if (d>=0)
{x1=(-b-sqrt(d))/(2*a);
x2=(-b+sqrt(d))/(2*a);
cout<< “\nx1=”<<x1<<“x2=”<<x2;
}
else cout<<“\nРозвязку немає”;
Якщо оператор1 та/або оператор2 містять два або більше операторів, їх беруть у фігурні дужки {}, тобто вони є складовими. Оператор if перевіряє істинність чи хибність умови. Якщо умова справджується (не рівна 0), тоді виконується оператор1, інакше, при хибності умови (==0), виконується оператор2.
Другу частину оператора (else оператор2;) можна опускати. Така його форма має назву “скороченої”. Тоді у випадку хибності умови, керування передається до оператора, що йде услід за умовним оператором.
Якщо оператор1 і оператор2 в свою чергу є операторами if , вони є вкладеними.
Загальний вигляд вкладеного оператора if: if (умова1) оператор1;
else if (умова2) оператор2;
else оператор3;
В якості умов у мовах С/С++ використовуються стандартні операції відношення: <, <=, >, >=, !=, ==. Пари наведених символів не можна відокремлювати чи переставляти.
Для об’єднання в умові декількох умов використовуються логічні операції. Наведемо їх перелік в порядку спадання пріоритету: ! (заперечення або логічне НІ), && (кон’юнкція або логічне І), || (диз’юнкція або логічне АБО). Між позначками && та || не дозволяються пробіли.
Наприклад: 0<x&&x<=100
((!x)&&(y>0)||((z==1)&&(k>0))
Оператор вибору switch подібний до умовного оператора if, проте у ньому замість виразу-умови використовується вираз, результатом якого може бути декілька цілочисельних значень, кожне з яких, вимагає виконання свого оператора. Отже, програму можна спрямувати більше ніж у двох напрямках.
Загальна форма запису оператора вибору:
switch(вираз)
{ case consnant1: оператори; break;
сase consnantN: оператори;break;
default: оператори; },
де consnant1…consnantN - цілі або символьні константи. При виконанні оператора switch, обраховується вираз, записаний після switch і його значення послідовно порівнюється з константами, записаними після case. При першому ж співпаданні виконуються оператори, позначені даною міткою. Якщо виконувані оператори не містять оператор переходу break, далі виконуватимуться оператори усіх наступних варіантів. Якщо значення виразу, записаного після switch, не співпало з жодною константою, виконуватимуться оператори після мітки default, яка не є обов’язковою.
4.3 ОператорИ циклУ
Цикл з параметром for:
Основна форма запису:
for (вираз_1; вираз_2; вираз_3 ) оператор;
де вираз_1 – ініціалізація початкового значення параметру циклу;
вираз_2 – перевірка умови на продовження циклу;
вираз_3 – зміна параметру циклу з кожною ітерацією (корекція);
оператор – тіло циклу, простий або складовий оператор.
Цикл продовжується до тих пір, поки вираз_3 не стане рівним 0. Будь-який вираз можна опускати, залишаючи натомість “ ; ”.
Приклади використання циклу з параметром:
Зменшення параметра:
for ( n=10; n>0; n--)
{ <тіло циклу>}
Зміна кроку коректування:
for ( n=2; n>60; n+=13)
{ <тіло циклу>}
3)Корекція може здійснюватися не лише за допомогою додавання чи віднімання:
for ( d=100.0; d<150.0;d*=1.1)
{ <тіло циклу>}
for (x=1;y<=75;y=5*(x++)+10)
{ <тіло циклу>}
Можна використовувати декілька виразів ініціалізації або модифікації:
for (x=1, y=0; x<10;x++,y+=x)
{ <тіло циклу>}.
Цикл з передумовою while:
Основна форма запису:
while (умова)
оператор;
де оператор – це простий, складовий або порожній оператор.
Цикл виконується до тих пір, поки умова приймає значення “true”, тобто вираз у дужках повертає ненульовий результат. У циклі з передумовою спочатку перевіряється істинність умови, а потім виконується оператор тіла циклу. Тому цикл while не виконується жодного разу, якщо від початку умова буде хибною.
Цикл з післяумовою do – while:
Основна форма запису:
do
оператор;
while (умова);
де оператор – це простий, складовий чи порожній оператор.
Тіло циклу виконується до тих пір, поки умова справджується. Оскільки в циклі do–while умова перевіряється в кінці, оператор тіла циклу виконуватиметься хоча б один раз.
Для запобігання безкінечності циклу в тілі циклів while та do–while потрібно передбачити зміну параметрів, які входять до умови.
4.4 ОПЕРАТОРИ ПЕРЕХОДУ
Оператори переходу виконують безумовну передачу управління.
goto < мітка> - оператор безумовного переходу. Керування передається оператору з даною міткою:
<мітка>: оператор;
В мові С мітка не декларується.
break - оператор перериває цикл або перемикач, управління передається на перший наступний оператор;
while (умова)
{< оператори>
if (<вираз-умова>) break;
<оператори>}.
Тобто оператор break доцільно використовувати, коли умову продовження ітерації потрібно перевіряти в тілі циклу.
continue – припинення поточної і перехід до наступної ітерації циклу. Використовується, коли тіло циклу містить розгалуження.
3) return – здійснює повернення результату з тіла функції.
5. Вказівники та операції над ними
5.1 ПОНЯТТЯ ВКАЗІВНИКА
Кожна змінна у програмі - це об’єкт, який володіє ім’ям і значенням. Після визначення змінної з ініціалізацією всі звернення у програмі до неї за іменем замінюються компілятором на адресу іменованої області оперативної пам’яті, в якій зберігається значення змінної (Рис. 5.1). Програміст може визначити власні змінні для збереження адрес областей пам’яті. Такі змінні називають вказівниками.
int a=10;
Рис. 5.1.
Вказівник визначається наступним чином:
<тип> *< ідентифікатор> <ініціалі затор>;
Приклад 1. Визначення вказівників
int* pa=&a;// вказівник ра містить значення адреси змінної а
float *ptr (NULL); // Нульовий вказівник на об’єкт типу float
char*p; // Неініціалізований вказівник на об’єкт типу char
Значення адреси змінної одержується за допомогою унарної операції ”&”.
Для доступу до комірки пам’яті, виділеної під змінну через вказівник до останнього, слід застосувати унарну операцію розіменування ”*”.
Приклад 2. Непряма адресація через вказівник
int x=2; //змінна типу int
int *y =&x;// вказівник на елемент даних типу int
*y=1; // через вказівник до поля x вноситься значення 1,
//тобто x=1
p=new char(12);
В останньому операторі прикладу 2 неініціалізований вказівник р, описаний у прикладі 1, асоціюється з ділянкою у динамічній пам’яті під змінну типу char, до якої заноситься значення 12.
5.2 ДІЇ НАД ВКАЗІВНИКАМИ
Приклад 3: Дії над вказівниками
int a=5;
int *p=&a, *p2, *p2; p2=p1=p;
++p1; p2+=2;
cout<<“a=”<<a;
cout<<” p=”<<*p<<” p=”<<p<<” p1=”<<p1<<” p2=”<<p2;
Результат виконання:
a=5, *p=5, p=FFC8, p1=FFCC, p2=FFD0.
Конкретні значення адрес залежать від низки причин: архітектури комп’ютера, типу і розміру оперативної пам’яті тощо.
З арифметичних операцій між вказівниками дозволена лише операція віднімання.
Різницею двох вказівників одного типу є відстань між двома областями пам’яті, кратна довжині (в байтах) об’єкта того типу, якому відповідає вказівник. Різниця однотипних вказівників, що адресують суміжні об’єкти, за абсолютною величиною рівна одиниці. Адреси змінних позначаються цілочисельними 16-ковими константами.
Ті змінні, визначення яких розміщені в програмі поруч, займають суміжні ділянки пам’яті, проте розміщення об’єктів у пам’яті є оберненим в порівнянні з їх взаємним розташуванням у визначеннях тексту програми.
До вказівника дозволено додавати і віднімати цілочисельну константу (k). При цьому він пересувається між ділянками пам’яті на величину k*(sizeof(type)).
6. Робота з одновимірними масивами
6.1 СТАТИЧНІ ТА ДИНАМІЧНІ МАСИВИ
Масив – це кінцева послідовність даних одного типу. Кожен елемент масиву має однакове ім’я – ім’я масиву, і відрізняється індексом (ціле число), за яким здійснюється доступ до елемента масиву. Індекси масивів у С/С++ починаються з 0. У програмі одновимірний масив оголошується наступним чином:
<тип> <ім’я масиву> [розмір] <ініціалізація>; ,
де розмір – кількість елементів одновимірного масиву.
Після визначення ім’я масиву стає вказівником-константою, значення якого є незмінним і становить адресу першого (нульового) елемента масиву.
За способом розміщення масиви поділяються на статичні та динамічні. Розмір статичного масиву можна задавати константою або константним виразом. Оскільки ділянка у оперативній пам’яті під масив задається на етапі компіляції і її розмір визначається типом елементів масиву та їх кількістю, розмірність масиву повинна бути визначена у тексті програми, а не підчас її виконання. Для визначення масиву змінного розміру використовується механізм динамічного виділення пам’яті.
Наприклад:
- оголошення одновимірного масиву з п’яти елементів цілого типу:
int a[5];
- динамічне виділення пам’яті під 10 цілочисельних елементів:
int*m=new int [10];
Враховуючи те, що імя масиву є вказівником, зрозумілим стає зміст останньої операції: вказівникові на int m присвоюється початкова адреса ділянки памяті, виділеної у динамічній області під 10 цілочисельних елементів.
Перевагою динамічних масивів є те, що їх розмірність може бути змінною, тобто у програмі можна працювати з масивами довільного розміру, не вносячи змін до тексту програми. Проте, динамічні масиви не можна ініціалізувати при визначенні і вони за замовчуванням не заповнюються нулями.
Натомість ініціалізацію статичних масивів можна здійснювати при їх визначенні. При цьому слід зауважити, що у С/С++ не перевіряється вихід індексу за межі масиву.
Наприклад:
double d[] = {1, 2, 3, 4, 5};
float f[10]={1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.0};
При поєднанні визначення масиву з ініціалізацією його розмірність у квадратних дужках можна не вказувати. Довжину масиву компілятор визначить за кількістю значень, наведених у фігурних дужках.
Для звернення до елементів масивів використовуються два способи, наприклад до 4-го (по порядку) елемента масиву a можна звернутися як a[3] або *(a+3). Останнє звернення базується на факті, що ім’я масиву є одночасно вказівником на його нульовий елемент, а зміщення вказівника у пам’яті відбувається на величину індексу помножену на розмір типу елементів масиву у байтах.
Пам’ять, зарезервовану під динамічний масив за допомогою new[ ], потрібно звільняти оператором delete [] <імя массиву>.
Отже, якщо кількість елементів масиву відома до виконання програми, краще використовувати статичний масив, розмірність якого позначити як значення іменованої константи. Якщо розмірність масиву необхідно задавати в процесі виконання програми (до введення його елементів), то доцільно створювати динамічний масив.
6.2 РЯДКИ, ЯК ОДНОВИМІРНІ МАСИВИ СИМВОЛІВ
У мовах С/С++ немає окремого типу даних “рядок символів”, подібно до типу string у алгоритмічній мові PASCAL. Тому робота з рядками реалізована шляхом використання одновимірних масивів типу char. Рядок символів – це одновимірний масив типу char, останнім елементом якого є нульовий байт. Нульовий байт – це байт, кожен біт якого рівний нулю, при цьому для нульового байта визначена символьная константа \0 (ознака закінчення рядка або нуль-термінатор). Тому, якщо рядок містить k символів, в описі масиву потрібно вказати розмірність k+1.
Так, для збереження у масиві рядкової константи “Лабораторна робота з рядками”, необхідно описати масив char s[29]. В кінці рядкової константи символ ´ \0 вказувати не потрібно, оскільки це зробить компілятор мови С.
Рядки можна
а) ініціалізувати при декларуванні.
Наприклад:
charS1[10]=”123456789”,S2[]=”abcdefg”,S3[]={‘1’,‘2’,‘3’,‘\0’};,
де в двох останніх випадках розмір рядків буде встановлений за кількістю символів;
б) вводити з клавіатури, не використовуючи при цьому оператора циклу, подібно звичайним масивам.
Наприклад:
char Tоріс[20];
cout<<”Введіть тему лабораторної роботи:\n”; cin>>Tоріс;
7. Двовимірні масиви
Крім одновимірних масивів у С/С++ можливо працювати з багатовимірними масивами, а найчастіше з двовимірними матрицями. Двовимірний масив – це масив, що складається з окремих одновимірних масивів у вигляді рядків, розмірність яких рівна кількості стовпців матриці. Для цього при визначенні двовимірного масиву у квадратних дужках вказується дві розмірності. Оператор опису двовимірного масиву має вигляд:
<тип> <ім’я> [<розмір1>][<розмір2>];
Наприклад:
int a[3][5]; // Цілочисельна матриця з 3 рядків і 5 стовпців
Масив зберігається у неперервній області пам’яті по рядках, які зберігаються послідовно один за одним, а не у вигляді звичної з матики матриці:
a>00 >a>01> a>02> a>03> a>04> a>10> a>11> a>12> a>13> a>14> a>20> a>21> a>22> a>23> a>24>
| -0-ий рядок- - |-- 1-ий рядок - |- - 2-ий рядок- - |
Для доступу до окремого елемента двовимірного масиву використовується конструкція, яка має вигляд a[i][j], де i – номер рядка, j – номер стовпчика. Кожен індекс може змінюватися від 0 до значення, яке на одиницю менше за значення відповідної розмірності.
Як і для одновимірного масиву, при описі двовимірного масиву можна задавати початкові значення його елементів. Їх записують у фігурних дужках. Елементи масиву ініціалізуються в порядку їх розміщення у пам’яті.
Наприклад: оператор
int с[3][4] = {1,2,34,2,3,4,1,3,4,1,2};
визначає матрицю з наступними значеннями елементів: 1 2 3 4
2 3 4 1
3 4 1 2
Можна задавати початкові значення не для всіх елементів масиву. Для цього список значень для кожного рядка береться додатково у фігурні дужки. Наприклад:
int d[3][4] = {{0,1,2},{9,-2},{-7,1,6,8}};
В даному випадку розмірність, що позначає кількість рядків, можна не вказувати.
Для створення динамічного двовимірного масиву необхідно вказати в операції new всі його розмірності, причому ліва розмірність (кількість рядків) може бути змінною:
int nriad=5;
int **m=(int**) new int[nriad][10];
Більш ефективний і безпечний спосіб виділення пам’яті під двовимірний масив, коли обидві його розмірності вказуються на етапі виконання програми, тобто є змінними, наведено нижче:
int nriad, nstp;
cout <<”Введіть кількість рядків та стовпців:”;
cin >> nriad >> nstp;
int**a = new int *[nriad];// 1
for (int i=0; i < nriad; i++)// 2
a[i] = new int[nstp];// 3
В операторі 1 оголошується змінна типу ”вказівник на вказівник на int” і виділяється пам’ять під масив вказівників на рядки масиву (nriad – кількість рядків). В операторі 2 організовано цикл для виділення пам’яті під кожен рядок масиву. В операторі 3 кожному елементу масиву вказівників на рядки присвоюється адреса початку ділянки пам’яті, виділеної під рядок двовимірного масиву з кількістю елементів типу int у ній, рівною nstp
8. Символьна інформація та рядки
8.1 ЗБЕРЕЖЕННЯ СИМВОЛЬНОЇ ІНФОРМАЦІЇ
Для символьних даних в C/С++ введено тип char. Для представлення символьної інформації використовуються символи, символьні змінні і текстові константи. Приклади:
const char c=’c’; //символ-константа – займає один байт
char a,b; // символьні змінні, займають по одному байту
const char *s=“Приклад рядка\n” ; // рядкова константа
Рядок в С++ - це масив символів, що закінчується нуль-символом ‘\0’. За місцезнаходженням цього символу визначається фактична довжина рядка. Кількість елементів у такому масиві на 1 більше за зображення рядка (рис. 8.1).
A |
\0 |
A |
|
“A” рядок (2 байти) |
‘A’ символ (1байт) |
Рис. 8.1.
Рядок розміщується у масиві або за допомогою операції вводу з клавіатури, або за допомогою ініціалізації.
Приклади:
char s1[10]="string1"; // масив символів з десяти елементів
char s3[]={‘s’,’t’,’a’,‘r’,’t’,’\0’}; // масив з 6 елементів типу char
сhar *s4="string4"; // вказівник-змінна на рядок
char *s=”String5”; // виділяється 8 байтів для рядка
char *sss=new char[10]; /* виділяється динамічна пам’ять
під 10 елементів типу char*/
strcpy(sss,”Thanks”);// у цю область пам’яті копіюється рядок.
8.2 ФУНКЦІЇ ВВОДУ/ВИВОДУ ПРИ РОБОТІ З РЯДКАМИ
Для вводу і виводу символьних даних у бібліотеці мови С (файл <stdio.h>) визначені наступні функції:
int getchar() - здійснює введення одного символу з вхідного потоку і повертає один байт інформації (символ) у вигляді значення типу int. Це робиться для розпізнавання ситуації, коли при зчитуванні буде досягнуто кінець файлу.
int putchar (int c) – розміщує в стандартний вихідний потік символ c.
Приклад:
# include <stdio.h>
void main()
{char c, d;
c=getchar(); putchar(c);
d=getchar(); putchar(d);
}
char* gets(char*s) – зчитує рядок s із стандартного потоку до появи символу ‘\n’, сам символ ‘\n’ у рядок не заноситься. Повертає вказівник на цей рядок.
int puts(const char* s) – записує рядок у стандартний потік виводу, додаючи в кінці рядка символ ‘\n’, у випадку вдалого завершення повертає значення більше або рівне 0 і від’ємне значення у випадку помилки.
Також для вводу/виводу рядка можна використовувати функції scanf/printf, відповідно, задавши специфікатор формату %s:
# include <stdio.h>
void main(){
const int n=10;
char s[n];
scanf(“%s”, s); printf(“%s”, s);}
Ім’я масиву є вказівником-константою на початок рядка, тому не слід застосовувати операцію взяття адреси (&), що зазвичай використовується з функцією вводу scanf. Ввід буде здійснюватися до першого символу пропуску. Для того щоб ввести рядок, який складається з декількох слів, використовується специфікатор %c (символи) із зазначенням у ньому максимальної кількості символів, що вводяться, наприклад:
scanf(“%10c”, s);
При виводі рядка на екран можна в специфікації %s зазначити кількість символів, які відводяться під рядок:
printf(“%15s”, s);
Функції вводу/виводу мови С++, описані у заголовному файлі <iostream.h>:
cin>>s; //ввід рядка зі стандартного потоку до появи першого пропуску.
При введенні, наприклад, рядка “Ваня Іванов” в рядок s буде записано лише перше слово рядка, а саме “Ваня\0”.
cout<<s; //вивід рядка в стандартний потік до першого пропуску.
Якщо потрібно ввести рядок, який складається з декількох слів, в одну рядкову змінну, використовують методи getline або get класу istream, об’єктом якого є cin. Виклик цього методу здійснюється наступним чином: після імені об’єкту cin ставиться крапка, за якою записується ім’я методу:
#include<iostream.h>
int main()
{const in n=80;
char s[n];
cin.getline(s, n); cout<<s<<endl;
cin.get(s, n); cout<< s}
Метод getline зчитує з вхідного потоку n-1 символів або менше (якщо символ переводу рядка зустрінеться раніше) і записує їх у рядкову змінну s. Символ переводу рядка також зчитується (видаляється) з вхідного потоку, але не записується у рядкову змінну, замість нього розміщується завершальний ’\0’. Якщо в рядку вихідних даних більше за n-1 символів, наступне введення буде виконуватися з того ж рядка, починаючи з першого символу, що не був зчитаний.
Метод get працює аналогічно, але залишає в потоці символ переводу рядка. До рядкової змінної додається завершальний ’\0’.
8.3 СПЕЦІАЛЬНІ ФУНКЦІЇ ДЛЯ РОБОТИ З РЯДКАМИ ТА СИМВОЛАМИ
Для рядків не визначено операцій присвоювання, додавання, порівняння, оскільки рядок не є основним типом даних. Для роботи з рядками використовуються спеціальні бібліотечні функції, опис яких міститься у файлі <string.h>. Деякі з цих функцій наведено у таблиці 8.1:
Таблиця 8.1 Функції стандартної бібліотеки для роботи з рядками – файл <string.h>
Прототип функції |
Короткий опис та використання |
Пояснення |
unsigned strlen(const char*s); |
Обчислює довжину рядка s. strlen(s); |
Повертає фактичну довжину рядка, не враховуючи нуль-символ |
int strcmp(const char*s1, const char *s2); |
Порівнює рядки s1 і s2. strcmp(s1, s2); |
Якщо s1<s2, тоді результат від’ємний, якщо s1= =s2, тоді результат рівний 0, якщо s2>s1 – результат додатний. |
int strncmp(const char*s1, const char *s2, n); |
Порівнює перші n символів рядків s1 і s2. strncmp( s1, s2, n); |
Якщо n(s1)<n(s2), тоді результат від’ємний, якщо s1= =s2, тоді результат рівний 0, якщо s2>s1 – результат додатний. |
char*strcpy(char*s1, const char*s2); |
Копіює символи рядка s2 у рядок s1. strcpy(s1, s2); |
Нуль-символ при цьому теж включається |
char*strncpy(char*s1, const char*s2, int n); |
Копіює n символів рядка s2 у рядок s1. strncpy(s1,s2,n); |
Кінець рядка відкидається. Якщо нуль-символ у вихідному рядку зустрінеться раніше, копіювання припиняється, а решта символів рядка доповнюються ‘\0’-ми. |
char*strcat(char*s1, const char*s2); |
Дописує рядок s2 до рядка s1. strcat(s1, s2); |
Перший символ s2 записується на місце нуль-символу рядка s1. До результуючого s1 додається ‘\0’. |
char*strncat(char*s1, const char*s2, size_t n); |
Дописуються перші n символів рядка s2 до рядка s1. strncat(s1,s2,5); |
n-символів рядка s2 записується до s1, починаючи з місця нуль-символу s1. |
char* strсhr(char*s, int ch) |
Шукає символ ch у рядку s. strchr(s, ch); |
Повертає вказівник на перше входження символу в рядок справа. Якщо його немає – повертається NULL |
char* strrev(char *s1) |
Змінює порядок символів у рядку s1 на протилежний. strrev(s1, s2); |
Дзеркальне відображення рядка s1. |
char *strstr(char*s1, char*s2) |
Шукає підрядок у рядку. strstr(s1, s2); |
Пошук першого входження s2 у s1. В разі вдалого пошуку повертається вказівник на елемент з s1, з якого починається s2, інакше – NULL. |
char *strtok(char*s1, char*s2) |
Розбиває рядок на лексеми. strtok(s1, s2); |
Функція повертає вказівник на лексему в s1, відокремлену символом з набору s2 (пробілами або розділовими знаками). |
Для роботи з символами у файлі <ctype.h> стандартної бібліотеки визначено функції, наведені в таблиці 8.2:
Таблиця 8.2 Функції стандартної бібліотеки для роботи з символами-файл <ctype.h>
Прототип функції |
Короткий опис та використання |
Пояснення |
int isalnum(int ch) |
Перевіряє чи є символ ch буквою або цифрою (A-Z, a-z, 0-9). isalnum(ch); |
Повертається true, якщо ch є буквою або цифрою, інакше false |
int isalpha(int ch) |
Перевіряє чи є символ ch буквою (A-Z, a-z). isalpha(ch); |
Повертається true, якщо ch є буквою, інакше false |
int isspace(int ch) |
Перевіряє чи є символ ch пропуском (пробіл, табуляція, символ нового рядка, нової сторінки). isspace(ch); |
Повертається true, якщо ch є узагальненим пробілом, інакше false |
int isdigit(int ch) |
Перевіряє чи є символ цифрою (0-9). isdigit(ch); |
Повертається true, якщо ch є цифрою, інакше false |
int islower(int ch) |
Перевіряє чи є символ буквою нижнього регістру (a-z). islower(ch); |
Повертається true, якщо ch є буквою нижнього регістру, інакше false |
int isupper(int ch) |
Перевіряє чи є символ буквою верхнього регістру (A-Z). isupper(ch); |
Повертається true, якщо ch є буквою верхнього регістру, інакше false |
int ispunct(int ch) |
Перевіряє чи є символ символом пунктуації (. , : ; ? ! тощо). ispunct(ch); |
Повертається true, якщо ch є символом пунктуації, інакше false |
int tolower (int ch) |
Повертає символ у нижньому регістрі. tolower (int ch); |
Одержує символ ch і повертає його у нижньому регістрі |
int toupper(int ch) |
Повертає символ у верхньому регістрі. toupper(int ch); |
Одержує символ ch і повертає його у верхньому регістрі |
Приклад 1:
Дано рядок символів, що складається зі слів, слова відокремлені пропусками. Видалити з рядка всі слова, що починаються з цифри.
#include <iostream.h>
#include <string.h>
#include <ctype.h>
void main()
{const int n=250;// розмірність рядкового масиву
char s[n], // вихідний рядок
w[25], // проміжний масив для збереження слова з рядка
*mas[10];// масив вказівників для збереження слів з рядка
cout<<“\nBведiть рядок:\n”;
cin.getline(s, n);
int k=0, t=0, i, len, j;
len=strlen(s);
while(t<len)
{ for(j=0,i=t; isspace(s[i])==0; i++,j++)
w[j]=s[i]; // виокремлюємо слово до пробілу
w[j]=’\0’;// формуємо кінець слова
strcpy(mas[k],w);// копіюємо слово у масив
k++;// збільшуємо лічильник слів у рядку
t=i+1;// перехід через пробіл до наступного слова у
// вихідному рядку s
}
strcpy(s,” ”);// очищуємо вихідний рядок
for(t=0; t<k; t++)// заповнюємо рядок
if(isalpha(mas[t][0])!=0){// якщо перший символ не цифра
{strcat(s,mas[t]);// дописуємо слово в оновлений рядок
strcat(s,” “);// додаємо пробіл після слова
}
cout<<”\nНовий рядок:\n”<< s;// виводимо результат
}
Приклад 2:
Програма яка підраховує скільки разів задане слово зустрічається у тексті файлу. Наприклад, у англійській поговірці “Don’t trouble trouble until trouble troubles you” слово “trouble” у чистому вигляді зустрічається 3 рази.
#include <fstream.h>
#include <string.h>
# include<ctype.h>
void main()
{const int len=81;
char word[len], line [len];// масиви для слова і рядка
cout<< “Введiть слово для пошуку:”; cin>> word;
int_lword=strlen(word);// визначення довжини слова
ifstream fin (“text.txt”, ios:: in | ios:: nocreate);
if(!fin) {cout<< “Помилка відкриття файлу.”<<endl;return 1;}
int count=0;
// поки не досягнуто нуль-символу
while(fin.getline(line, len))
{char *p=line;// вказівникові присвоєно адресу рядка
while(p=strstr(p,word))/* якщо слово знайдено
вказівник стає на позицію
початку слова у рядку*/
{ // адреса початку входження слова передається с
char * c=p;
p+=l_word;// перехід вказівника р через слово
// слово не на початку рядка
if(c!=line)
/* Чи є символ перед словом розділювачем? Інакше –
перейти до наступної ітерації */
if(!ispunct(*(c-2))&& isspace(*(c-1))) continue;
// Чи є символ після слова розділювачем?
if (ispunct(*p)|| isspace(*p)|| (*p==’\0’)) count ++;
}
}
cout << “Слово зустрічається в тексті ”<< count;
<<” разів”<<endl;
}
9. Функції користувача
9.1 ФУНКЦІЇ: ВИЗНАЧЕННЯ, ОПИС, ВИКЛИК
Функцію в С++ можна розглядати:
як один з похідних типів даних (поряд з масивами і вказівниками);
як мінімальний виконуваний модуль програми (підпрограму).
Всі функції мають однаковий формат визначення:
<тип><ім’я_функції>(<список_формальних_параметрів>)
<тіло_функції>,
де <тип> - тип результату, який повертається функцією; в разі, якщо функція не повертає ніякого значення, її специфікують типом void і називають “порожньою”. Найчастіше, це функції, які виводять на екран повідомлення чи виконують деякі зміни параметрів, проте не можуть передати певний результат іншим змінним при виклику.
<ім’я_функції> - або main для головної функції, або довільний ідентифікатор;
<список_формальних_параметрів> - або порожній ( ), або список, кожен елемент якого записується як:
<тип> <ім’я_формального_параметру>
Наприклад:
(int k )
(char i, char j, int z)
<тіло_функції> - це набір операторів, що виконуються у фігурних дужках {} при виклику функції. Тіло функції може бути складовим оператором або блоком. Визначення функцій не можуть бути вкладеними.
Для передачі результату з функції у функцію, що її викликала, використовується оператор return. Його можна використовувати у двох формах:
return 0; - завершує функцію, яка не повертає ніякого значення (тобто перед її іменем вказано тип void);
return <вираз>; - повертає значення виразу, тип виразу повинен співпадати з типом функції.
Приклад 1:
int op (char c, int x, int y)
{switch (c)
{case ‘+’ : return x+y;
case ‘-’ : return x-y;
case ‘*’ : return x*y;
case ‘/’ : return x/y;
default: cout<<“\nОперація не визначена!”;
return 0;
}
}
Приклад 2.
float cube(float d)
{return d*d*d;}
Після визначення функцію можна багаторазово використовувати у програмі для виконання однотипних дій над різними змінними.
Виклик функції має наступний вигляд:
<ім’я_функції>(<список фактичних параметрів>);
<список фактичних параметрів - або сигнатура, є переліком виразів, кількість яких дорівнює кількості формальних параметрів функції. Між формальними і фактичними параметрами повинна бути відповідність за типами. В якості фактичних параметрів можна використовувати змінні, визначені та ініціалізовані у програмі, з типами, що відповідають типам формальних параметрів. Якщо функція повертає значення, її виклик можна використати у правій частині операції присвоювання з метою передачі результату функції змінній, тип якої співпадає з типом функції, що викликається.
Наприклад:,
void main(){float s, f=0.55; s=cube(f);…}
В якості фактичних параметрів також можуть виступати явно задані константні значення:
Наприклад, виклик функції з прикладу 1 має наступний вигляд:
c = op ( ‘+’, 5 ,4 );
Оскільки визначення функцій не можуть міститися всередині блоків та складових операторів, тобто в інших функціях, у програмі вони можуть розміщуватися як до, так і після функції, яка їх викликає. В останньому випадку перед використанням функції у програмі необхідно розмістити її опис, або прототип, інакше виникатимуть проблеми. Компілятор передусім послідовно перевіряє коректність виклику та використання обєктів у програмі, при виявленні функції, яка не була описана чи визначена раніше, видасть повідомлення про помилку і вказівку про те, що функція повинна містити прототип. Те саме повідомлення Ви побачите на екрані, якщо використаєте у програмі функцію зі стандартних бібліотек і не підєднаєте заголовний файл, у якому вона описана. Прототип функції користувача багато в чому нагадує заголовок функції і має наступний формат:
<тип><ім’я_функції>(<список_формальних_параметрів>);
Головною відмінністю є наявність в кінці опису крапки з комою.
Так, прототипи функцій з прикладів 1 та 2 матимуть вигляд:
cube(float);
op(char c, int, int);
Прототип надає компіляторові інформацію про тип та імя функції, а також про типи, кількість та порядок розміщення параметрів, які їй можна передавати. Зважаючи на це, імена формальних параметрів зазначати необовязково. Прототип являє собою зразок для здійснення синтаксичної перевірки компілятором.
9.2 ПЕРЕДАЧА МАСИВІВ У ФУНКЦІЮ
Якщо в якості параметру функції використовується позначення масиву, необхідно передати до функції його розмірність.
Приклад 3: Обчислення суми елементів масиву
int sum (int n, int a[] )
{ int i, s=0;
for( i=0; i<n; i++ )
s+=a[i];
return s;
}
void main()
{ int a[]={ 3, 5, 7, 9, 11, 13, 15 };
int s = sum( 7, a );
cout<<s;
}
Рядки в якості фактичних параметрів можуть визначатися або як одновимірні масиви типу char[], або як вказівники типу char*. На відміну від звичайних масивів, для рядків немає необхідності явно вказувати довжину рядка, оскільки будь-який рядок обмежується нуль-символом.
При передачі у функцію двовимірного масиву в якості параметру так само необхідно задавати кінцеві розміри масиву у заголовку функції. Робити це можна:
а) явним чином (а[3][4] тоді функція працюватиме з масивами лише заданої розмірності);
б) можна спробувати для квадратної матриці через додатковий параметр ввести розмірність (void matrix(double x[][], int n)), де n – порядок квадратної матриці, а double x[][] – спроба визначення двовимірного масиву зі заздалегідь невизначеними розмірами. В результаті на таку спробу компілятор відповість: Error…: Size of type is unknown or zero;
в) найзручнішим вважається спосіб представлення та передачі двовимірної матриці за допомогою допоміжних масивів вказівників на одновимірні масиви, якими в даному випадку виступають рядки двовимірного масиву. Всі дії виконуються в межах рядків, розмір яких передається у функцію за допомогою додаткового формального параметру або з використанням глобальних змінних.
Приклад 4.
# include<iostream.h>
//Функція транспонування квадратної матриці
void trans (int n, double*p[])
{double x;
for (int i=0; i<n-1; i++)
for(int j=i+1; j<n; j++)
{x=p[i][j];
p[i][j]=p[j][i];
p[j][i]=x;
}
}
void main(){
// Задано масив для транспонування
double A[4][4]={11, 12, 13, 14
21, 22, 23, 24
31, 32, 33, 34
41, 42, 43, 44};
// Допоміжний двовимірний масив вказівників
double * ptr[]={(double*)&A[0], (double*)&A[1],
(double*)&A[2], (double*)&A[3]};
// Виклик функції
int n=4;
trans(n, ptr);
for(int i=0; i<n;i++)
{cout<<”\n Рядок ”<<(i+1)<<”:”;
for(int j=0; j<n; j++)
cout<<”\t”<< A[i][j];
}
}
9.3 ПЕРЕВАНТАЖЕННЯ ФУНКЦІЙ У С++
Перевантаження полягає в тому, що функція з одним іменем по різному виконується і повертає значення різних типів при передачі до неї фактичних параметрів у різній кількості та з різними типами. Для забезпечення перевантаження функцій необхідно для одного імені функції визначити заголовок і набір операторів для всіх функцій, що пов’язані з ним.
Приклад 5:
#include <iostream.h>
int max_element ( int n, int a[])
// знаходить максимальний елемент для масиву типу int
{
int max=a[0];
for ( i=1; i<n; i++)
if (a[i]>max) max=a[i];
return max;
}
long max_element ( int n, long a[])
// знаходить максимальний елемент для масиву типу long
{
long max=a[0];
for ( i=1; i<n; i++)
if (a[i]>max) max=a[i];
return max;
}
double max_element ( int n, double a[])
// знаходить максимальний елемент для масиву типу double
{
double max=a[0];
for ( i=1; i<n; i++)
if (a[i]>max) max=a[i];
return max;
}
float max_element ( int n, float a[])
// знаходить максимальний елемент для масиву типу float
{
float max=a[0];
for ( i=1; i<n; i++)
if (a[i]>max) max=a[i];
return max;
}
void main ( )
{
int x[]={10, 20, 30, 40, 50, 60};
long y[]={12L, 44L, 22L, 37L,30L};
int m1=max_element(6, x );
long m2=max_element(5, y);
}
9.4 ФУНКЦІЇ ЗІ ЗМІННОЮ КІЛЬКІСТЮ ПАРАМЕТРІВ
У мовах С та С++ допускаються функції, кількість параметрів у яких при компіляції не визначена. Крім того, можуть бути невідомими і типи параметрів. Кількість і типи параметрів стають відомими лише в момент виклику функції, коли явно задається список фактичних параметрів. Формат заголовку функції зі змінним переліком параметрів має вигляд:
<тип> <ім’я> (<специфікація_формальних_параметрів, …>)
Проте, кожна функція зі змінним переліком параметрів повинна мати механізм визначення їх кількості або типу. Для цього використовують два основні підходи:
1) Передача у функцію значення реальної кількості фактичних параметрів за допомогою одного або декількох обов’язкових параметрів;
2) Додавання до списку фактичних параметрів спеціального параметру-індикатора з унікальним значенням, яке буде сигналізувати про кінець списку.
Підхід (1) демонструє програма у прикладі 6, яка містить функцію зі змінним списком параметрів, перший з яких визначає кількість фактичних параметрів, що використовуються при викликанні функції:
Приклад 6:
# include <iostream.h>
// Функція сумує значення параметрів типу int
long summa (int k,…)// k – кількість параметрів, що додаються
{int *pik=&k;// вказівник, що звертається до параметрів функції
long total = 0;
for (;k;k--)// поки не вичерпано список параметрів
total+=*(++pik);// відбувається додавання
return total;// повернення результату
}
void main()
{// додаватимуться два параметри
cout<<”\n summa(2, 6, 4)=”<< summa(2,6,4);
// кількість параметрів, які потрібно додати - 6
cout<<”\n summa(6, 1, 2,3,4,5,6)= ”<< summa(6, 1,2,3,4,5,6);
}
Результат виконання:
summa(2,6,4)=10
summa(6,1,2,3,4,5,6)=21
Наступний приклад 7 ілюструє 2-й підхід до обмеження змінного списку параметрів. Програма містить функцію для визначення добутку змінної кількості параметрів. Ознакою кінця списку фактичних параметрів служить параметр з нульовим значенням.
Приклад 7:
# include <iostream.h>
double prod (doble arg, … )
{double aa=1.0;// початкове значення добутку
double *prt=&arg;// вказівник на перший елемент у списку
if (*ptr==0) return 0.0;// чи є перший елемент нулем?
for (; *ptr; ptr++) aa*=*ptr;// знаходження добутку
return aa;
}
void main()
{cout<< “\n prod(2.0, 4.0, 3.0, 0.0)=”<< prod (2.0, 4.0, 3.0, 0.0);
cout<<”“\n prod(1.4, 3.0, 0.0, 16.0)=”<< prod (1.4, 3.0, 0.0, 16.0);
cout<<“\n prod(0.0)=”<< prod (0.0);
}
Результат виконання:
рrod (2.0, 4.0, 3.0, 0.0)=24
рrod (1.4, 3.0, 0.0, 16.0)=4.2
рrod (0.0)=0.0
10. Структури
Структура об’єднує логічно зв’язані дані різних типів. При описі структури програміст створює новий тип, на основі базових або інших складових типів, за допомогою якого можна в подальшому описувати реальні об’єкти програми, які зберігатимуться у пам’яті. Склад цих об’єктів визначатиметься типом структури, за допомогою якої вони описуються. Структурний тип даних визначається описом:
struct <ім’я структури> {
<опис елементів>
};
Для виділення пам’яті під структуру необхідно визначити структурну змінну:
<ім’я структури> <ім’я змінної>;
Приклад 1.
struct lab{
int num;
char* name;
};// визначення структурного типу з іменем lab
lab Lаb_10;// опис конкретної структуриз іменем Lab_10.
Можна одночасно визначати структурний тип і описувати за допомогою нього структуру:
Приклад 2.
struct gr // ім’я структурного типу
{ char [10];// елемент структури
int year, nomer;// однотипні елементи структури
} grupa1; // ім’я структурної змінної
Елементи структури називають полями (num, name). Поля можуть бути будь-якого базового чи похідного типу, наприклад, масивом, вказівником, об’єднанням або іншою структурою.
Для звернення до полів структури використовуються уточнені імена через операцію вибору: “крапка” (“.”) при зверненні через ім’я структури і операцію непрямого доступу “->” при зверненні через вказівник.
Приклад 3.
Lab_10.num=10;
lab*ptrlab=&Lab_10;
ptrlab->name=”Структури”;
Ввід/вивід структур виконується поелементно (cin>>Lab_10.num;).
Структури одного типу можна копіювати.
Структури, пам’ять під які виділяється на етапі компіляції, можна ініціалізувати, перераховуючи значення їх елементів:
lab Lab10={10, “Структури”}.
Можна створювати масиви структур.
Приклад 4.
// структура для опису дати
struct date { int day,month,year;};
/* масив з 5-ти структур типу date , кожна з яких складається з 3-х елементів типу int, яким надаються початкові значення*/
date d[5]={ { 1,3,1980}, { 5,1,1990}, {1,1,2002}};
Приклад 5.
Програма, що демонструє використання структур для ведення обліку успішності студентів деякої академічної групи:
#include <conio.h>
#include <iostream.h>
struct Spysok {
char PIB[20];// масив для зберігання прізвищ студентів
char Grup[10];// номер групи
int Ot[3];// масив з трьох оцінок
float S_Bal;// середній бал
} *vid;// вказівник, на структуру
void Vvid(int nom, Spysok *vid)
{ cout << "\n Vvedit vidomosti \n" << (nom+1);
cout << "\n PIB - "; cin>>vid->PIB;
cout << " Nomer Gr - "; cin >> vid->Grup;
float s=0;
for(int i=0;i<3;i++) {
cout << "\n Otsinki - "; cin >> vid->Ot[i];
s+=vid->Ot[i];
}
vid->S_Bal=s/3;
}
void main()
{ struct Spysok Stud[50]; int i, N; char Litera;
clrscr();
cout << "\n Vvedit kilkist studentiv u grupi < 50 "; cin >> N;
for(i=0;i<N;i++) Vvid(i,&Stud[i]);
cout << "\n Spysok studentiv”;
for(i=0;i<N;i++)
cout<<"\n"<<Stud[i].PIB<<endl<<Stud[i].Grup<<endl<<Stud[i].S_Bal;
cout << "\n Poshuk vidomostey pro studentiv za pershoyu\ literoyu prizvyscha\n";
cin >> Litera;
if (islower(Litera)) toupper(Litera);
cout << "\n Vidomosti pro Students:";
int kod_p=0;
for(i=0;i<N;i++)
if(Stud[i].PIB[0]==Litera)
{ kod_p=1;
cout<<”\n"<<Stud[i].PIB
<<endl<<Stud[i].Grup<<endl<<Stud[i].S_Bal;
}
if(kod_p==0) cout << " Takyx nemae!";
getch();
}
Список використаної літератури
Подбельский В.В. Язык СИ++: Уч. Пособие. –5-е издание. –М.: Финансы и статистика, 2001. –560 с.
Подбельский В. В., Фомин С. С. Программирование на языке Си: Учеб. пособие. –М.:Финансы и статистика, 1998. –600с.
Павловская Т.А. С/С++. Программирование на языке высокого уровня: Учебник для ВУЗов. –СПб.:Питер, 2003. –461 с.
Павловская Т.А., Щупак Ю.А. С/С++. Практикум. –СПб.: Питер, 2002. –204 с.
Дейтел Х., Дейтел П. Как программировать на С++: Пер. с англ. –М.: Бином, 2000. –1024 с.
Прата С. Язык программирования С++. Лекции и упражнения. Учебник: Пер. с англ. –СПб.: ДиаСофтЮП, 2003. –1104 с.
Либерти Дж. Освой самостоятельно С++. –М.: Вильямс, 2001. –456 с.
Культин Н. С/С++ в задачах и примерах. –СПб.:БХВ-Петербург, 2001. –288 с.