Поможем написать учебную работу
Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.
Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.
МІНІСТЕРСТВО НАУКИ І освіти, молоді та спорту УКРАЇНИ
ХАРКІВСЬКИЙ національний УНІВЕРСИТЕТ РАДІОЕЛЕКТРОНІКИ
МЕТОДИЧНІ ВКАЗІВКИ
ДО ЛАБОРАТОРНИХ ТА ПРАКТИЧНИХ РОБІТ ПО КУРСУ
“ІНФОРМАТИКА ”
для студентів денної форми навчання
напряму підготовки 6.170103 - «Управління інформаційною безпекою».
кафедрою інформатики.
Протокол № __ від ____
ХАРКІВ 2011
Методичні вказівки до виконання лабораторних та практичних робіт з курсу “Інформатика” для студентів напряму підготовки 6.170103 - «Управління інформаційною безпекою».
/ Упоряд.: Сінельнікова Т.Ф.( Харків: ХНУРЕ, 2011. ( 102 с.))
Упорядники: Сінельнікова Т.Ф
ЗАГАЛЬНІ ПОЛОЖЕННЯ
Розвязання більшості наукових, інженерних і технічних задач тісно пов'язано з використанням обчислювальної техніки. Оволодіння основними поняттями комп'ютерної техніки і мовами програмування дозволить майбутньому інженеру ставити і вирішувати задачі на ЕОМ.
Основна мета даних методичних вказівок допомогти студентам придбати практичні навички по підготовці, налагодженню і розвязанню задач мовою програмування С++.
Приступаючи до виконання даного циклу лабораторних робіт, студенти зобов'язані ознайомитися з вимогами стандартів по оформленню схем алгоритмів і програм (ДСТУ).
У результаті виконання лабораторних робіт студенти повинні:
знати прийоми алгоритмізації і правила розробки і запису схем алгоритмів і програм мовою С++;
вміти складати схеми алгоритмів і розробляти програми, складати звіти відповідно до вимог ДСТУ, розв'зувати задачі на комп'ютері.
Виконання лабораторних робіт розраховано на активну самостійну роботу студентів. Кожна робота виконується студентом індивідуально згідно варіанта завдання, номер якого повинний збігатися з номером студента в журналі академ-групи.
Під час самостійної підготовки до заняття студенти повинні:
проробити теоретичний матеріал, рекомендований у методичних вказівках до роботи;
відповісти на контрольні питання ;
розробити схему алгоритму і скласти програму свого варіанту завдання;
оформити звіт по попередній лабораторній роботі і підготуватися до його захисту.
Студенти, що не мають до початку заняття рукописного тексту програми свого варіанту задачі, до заняття не допускаються!
При виконанні лабораторної роботи в аудиторії студентам необхідно відлагодити програму лабораторної роботи і одержати результати її виконання, а також захистити звіт за матеріалами попередньої лабораторної роботи.
Звіт про лабораторні роботи оформляється в зошиті і містить номер лабораторної роботи, тему і мету роботи, завдання, схему алгоритму, програми з результатами розвязання і висновки щодо роботи.
Правила техніки безпеки забороняють студентам вмикати і вимикати комп'ютери, а також доторкатись струмопровідних частин обладнання.
1 ОРГАНІЗАЦІЯ ВВЕДЕННЯ І ВИВЕДЕННЯ ДАНИХ
ТА РОЗВЯЗАННЯ ЗАДАЧ З ПРОСТОЮ ЗМІННОЮ
Освоїти прийоми роботи з текстовими редакторами і основними компонентами інтегрованого середовища програмування С++; отримати практичні навички введення - виведення даних, складання і налагодження програм із простими змінними; засвоїти правила опису типів даних; отримати навички у використанні операторів керування й організації циклів.
1.2 Вказівки до організації самостійної роботи студентів
При підготовці до роботи повторити типи констант і змінних, способи їхнього опису, використання операторів керування й організації циклів, а також використання інтегрованого середовища програмування на С++ [ 1, с. 70-72, с. 74-78; 2, c.7-22; конспект лекцій].
Звернути увагу, що в мові С++ немає убудованих у мову засобів введення і виведення. Усі дії, зв'язані з цими операціями, виконуються за допомогою функцій бібліотеки. Функції введення і виведення бібліотеки мови дозволяють читати дані з файлів і з пристроїв і писати дані у файли і на пристрої.
Бібліотека мови С++ підтримує такі три рівні введення виведення даних:
введення - виведення потоку;
введення - виведення нижнього рівня;
введення - виведення для консолі і порту.
При введенні - виведенні потоку всі дані розглядаються як потік окремих байтів. Для користувача потік це або файл на диску, або фізичний пристрій, наприклад, дисплей, чи клавіатура або друкувальний пристрій, з якого чи на який направляється потік даних. Функції введення - виведення для потоку дозволяють обробляти дані різних розмірів і форматів від одиночного символу до великих структур даних. Програміст може використовувати функції чи бібліотеки, розробляти власні і включати їх у бібліотеку. Для доступу до бібліотеки цих класів треба включити в програму відповідні файли заголовків, наприклад, #include <iostream.h>.
За замовчуванням стандартні введення, виведення і виведення повідомлень про помилки відносяться до консолі користувача (клавіатура і екран).
1.2.1 Використання операторів введення
Найчастіше в С++ використовується потокове введення даних, операції якого включені до складу класів istream або iostream . Воно може здійснюватися з визначеним у цих класах вхідним потоком cin або вихідним потоком, визначеним користувачем. Для читання символів з цього потоку вказується операція витягу з потоку, що позначається за допомогою символів “ >> “ . Це перевантажена операція, визначена для всіх простих типів і покажчика на char.
Формат запису оператора cin має вигляд:
cin [ >> values ]; .
Наприклад, для введення значень змінних x і y можна записати:
cin >> x >> y; .
Кожна операція “ >> “ передбачає введення одного значення. При введенні даних необхідно виконувати наступні вимоги:
для поділу двох чисел, що послідовно вводяться, використовується проміжок (дані типу сhаr розділяти проміжком не обов'язково) або ENTER;
якщо послідовно вводиться символ і число (або навпаки), проміжок треба записувати тільки в тому випадку, якщо символ, що вводиться, (типу сhаr) є цифрою;
потік введення ігнорує проміжки;
при введенні великої кількості даних одним оператором їх можна розташовувати в декількох рядках (використовуючи ENTER);
оператор введення з потоку припиняє свою роботу тоді, коли усі включені в нього змінні одержують значення. Наприклад, для раніше записаного оператора можна ввести значення таким чином:
2.345 789
або
2.345
789
Оскільки в цьому прикладі проміжок є роздільником між значеннями, що вводяться, то при введенні рядків, котрі містять проміжки у своєму складі, цей оператор не використовується. У такому випадку треба використовувати методи розглянутих класів такі як: getline( ), read( ), get( ) і ін. (формати цих функцій розглянемо при обробці символьних даних). У С++ операції введення - виведення можуть виконуватися з використанням операторів, а не функцій введення - виведення.
1.2.2 Організація виведення даних у мові С++
Виведення даних може бути неформатованим і форматованим. Найчастіше для виведення застосовується операція << , що записується разом з ім'ям вихідного потоку cout. Тобто, наприклад, запис
cout << x;
означає виведення значення змінної x ( або запис в потік). Цей оператор вибирає необхідну функцію перетворення даних у потік байтів.
Формат запису cout відрізняється від форми запису команд С++
cout << data << [ data ]; ,
де data це змінні, константи, вирази або комбінація типів.
Запис оператора cout може може мати, наприклад, такий вигляд:
сout << "y=" << x + a - sin(x) << "\n"; .
Оскільки у мові С++ операція “\n” рівнозначна операції endl, тому розглянутий оператор виводу можна записати як:
сout << "y=" << x + a - sin(x) << endl;
При використанні бульових операцій, вирази треба брати в дужки.
сout << "p =" << ( a && b || c ) << "\n"; .
Мова С++ не має символьних значень. Символ переводу на наступний рядок "\n" записується як строкова константа, інакше він розглядається не як керуючий символ, а як число 10 ( код символу). Таких помилок можна уникнути шляхом присвоєння значення керуючих символів змінним, наприклад:
#define <<sp " "
#define <<ht "\t"
#define <<hl "\n"
Тепер оператор виведення можна записати так:
сout << " y = " << x + a - sin(x) << hl; .
Слід пам'ятати, що cout не виконує автоматичний перехід на наступний рядок. Щоб надрукувати строкову константу, треба помістити її за оператором cout , тобто у такому вигляді:
cout << " Я вивчаю програмування \n";
або
cout << " Я вивчаю програмування”<< endl; .
Приклад 1.1 Наступний приклад містить організацію виведення даних, пояснюючі повідомлення , а також символи переводу рядка:
//P1_1.CPP ( роздрук значень змінних
// с відповідними позначками
#include <iostream.h>
int main ( )
{
char first = 'W';
char middle = 'P';
char last = 'S';
int wozrast = 20;
int doplata = 2;
float zarplata = 309.75;
float prozent = 8.5;
// Виведення результатів
cout << " Перевірка вихідних даних\n";
cout << first << middle << last << "\n\n";
cout << " Вік доплата зарплата відсоток: \n";
cout << wozrast << ' ' << doplata << ' ' << zarplata << ' ' << prozent;
return 0;
}
В останніх двох операторах використаємо символи табуляції. Наприклад, \t поміщає кожне наступне ім'я або число в наступну позицію табуляції (кожні вісім символів), у цьому випадку маємо:
cout << " Вік \t доплата\t зарплата\t відсоток\t \n";
cout << wozrast<<"\t" << doplata<<"\t"<< zarplata<<"\t"<< prozent<<"\n " ;
Для додаткового керування вихідними даними використовуються маніпулятори: setw(n) і setprecision(k). Маніпулятор setw(n) служить для вказівки довжини поля, що приділяється для виведення наступних даних (тут n - кількість позицій у рядку). Setprecision(k) призначений для вказівки кількості позицій у дробовій частині дробових чисел.
Маніпулятори змінюють вид деяких змінних в об'єкті cout, що у потоці випливають за ними. Ці маніпулятори називають прапорами стану. Коли об'єкт посилає дані на екран, він перевіряє прапори, щоб довідатися, як виконати завдання, наприклад, запис:
cout << 456 << 789 << 123;
видасть значення у вигляді: 456789123, що ускладнює визначити групи значень.
Приклад 1.2 Написати програму з використанням маніпулятора setw .
// P1_2.CPP ( демонстрація різних маніпуляторів
// ширини виведення цілого числа
#include <iostream.h>
#include <iomanip.h>
int main ( )
{
cout << 456 << 789 << 123 << endl;
cout << setw(5) << 456 << setw(5) << 789
<< setw(5) << 123 << endl;
cout << setw(7) << 456 << setw(7) << 789
<< setw(7) << 123 << endl;
return 0;
}
Результати виконання програми:
456789123
456 789 123
456 789 123
У цьому прикладі з'явився новий заголовний файл iomanip.h, що дозволяє використовувати функції маніпуляторів, таких як setw. При використанні функції setw, С++ вирівнює число вправо в границях заданої ширини поля виведення. Якщо ширина недостатня, С++ ігнорує вказане значення.
Функція setprecision(2) повідомляє С++ про те, що число з крапкою, що плаває, треба виводити з двома знаками після крапки з округленням дробової частини, наприклад, при виконанні оператора
сout << setw(7) << setprecision (2) << 123.456789;
буде отриманий наступний результат: 123.46.
Операція cin використовує ті ж маніпулятори , що й операція cout.
Приклад 1.3 Написати програму для обчислення податку на продажі.
// P1_3.CPP програма податок :введення суми продажів
// і роздрук податку на продажі
#include <iostream.h>
#include <iomanip.h>
int main ( )
{
float prod_sum; // Сюди буде записана сума продажів
float nalog ;
// Виведення підказки для користувача
cout << " Введіть суму продажів для розрахунку податку ";
cin >> prod_sum;
nalog = prod_sum* 0.7; // Обчислення податку на продажі
cout << " " << setprecision(2) << prod_sum;
cout << " " << setprecision(2) << nalog<< "\n";
return 0;
}
Через те, що в першому операторі cout не міститься знак переводу рядка, відповідь користувача на підказку з'явиться відразу праворуч від запиту.
Мова С++ широко використовує також форматоване введення і виведення даних. Для форматованого введення використовують функцію scanf, а виведення фукцію printf. Щоб зв'язати програму користувача зі стандартною бібліотекою, де знаходяться ці функції, необхідно спочатку програми передбачити препроцесорне ствердження
#include <stdio.h>
1.3 Використання основних операторів С++
У мові С++ прості оператори закінчуються символом ";", складені полягають у фігурні дужки. Розглянемо правила запису і використання основних операторів С++.
Оператор - вираз закінчуються крапкою з комою, наприклад:
++i; // інкремент
swap (&a, &y); // виклик функції
Оператори присвоювання мають одну з форм запису:
p =a ;
p =a = b = c;
де p ім'я змінної чи елемент масиву; а, b, с арифметичні вирази,
значення.
Оператор умовного переходу має наступний формат запису:
if (L)
оператор 1 ;
else
оператор 2 ; ,
де L логічний вираз. Якщо значення цього виразу “істина” (не нуль ), то виконується оператор1, якщо ж воно “не істина”(нуль), то виконується оператор2; у випадку, коли вираз помилковий й відсутнє else, виконується наступний оператор.
Наприклад, оператор умовного переходу може мати вигляд:
if ( i < j )
i++;
else
{ j = i - 3; i +=2; }
Оператор вибору використовують для вибору одного з багатьох варіантів вирішування і має наступну форму запису;
switch (L)
{
case к.в.1: оператор 1; [break;]
case к.в.2: оператор 2; [break;]
. . . . . . . . . . . . . . . . . . . . . . . . .
case к.в.n: оператор n; [break;]
[default: оператор n+1;]
} ,
де switch, case, default службові слова;
break оператор (необов'язковий) переривання виконання операторів switch;
L будь-який вираз одного з цілих типів;
к.в.1,…,к.в.n константні вирази, що не можуть повторюватися і не можуть містити змінних чи викликів функцій. Звичайно це ціла чи символьна константа;
оператор 1;. . . будь-які оператори С++.
Виконується цей оператор у такий спосіб: обчислюється значення виразу L, потім це значення порівнюється (послідовно зверху вниз) зі значеннями константних виразів к.в.1,.. і при збігу значень L і одного з к.в. будуть виконаються всі оператори починаючи з відповідного, якщо наприкінці немає оператора break. При наявності оператора break, виконується тільки оператор, що знаходиться у відповідній к.в. і управління передається оператору, що знаходиться за межами оператора switch. Якщо значення виразу L не збігається з жодним значенням к.в., то виконуються оператори з default і здійснюється вихід з оператора switch. У випадку, коли в цьому операторі немає default ( він не обов'язковий), і значення L не збігається з жодним зі значень к.в. , здійснюється вихід з оператора switch.
Можна привести наступний фрагмент програми з використанням оператора switch:
int a=2;
switch ( a )
{
case 1: func1( );
case 2: func2( );
case 0:
case 4: func3( );
default: printf ("gооd bay \n");
}
При виконанні цього оператора будуть реалізовані функції: func2, func3 і default: printf ("gud bay \n"); .
Даний приклад можна записати так само в наступному вигляді:
int a=2;
switch (a)
{
case 1: func1( ); break;
case 2: func2( ); break;
case 0:
case 4: func3( ); break;
default: printf ("gud bay \n");
} .
У такій реалізації буде виконана тільки case 2: func2( ); break; і вихід з оператора switch.
Мова С++ має такі оператори циклу: while, do, for.
Оператор циклу while L із предумовою
L будь-який простий, складений чи порожній оператор(будь-який припустимий вираз).
Виконується цей оператор у такий спосіб: якщо результат виразу L не дорівнює нулю (“істина”), то виконується цикл, а якщо дорівнює нулю (“неістина “), то цикл не виконується і керування передається наступному за while оператору.
Наведемо приклад використання оператора while .
Приклад 1.3: Обчислити значення функції:
Y= A*X*X-SIN(X) , якщо A=10.3; X[-1 ; +1]; hx=0.2.
// P1_6.CPP ( обчислення функції y = a* x* x sin (x)
// с використанням оператора циклу while
#include <stdio .h>
#include <math.h>
void main ( )
{
float a, x, y;
a = 10 . 3 ;
x = - 1 ;
while ( x <= 1)
{
y = a * x * x - sin(x)
printf ("x = % 4 f, y = % 6 f \n", x, y) ;
x = x + 0.2;
}
}
Оператор циклу for має наступну форму запису:
for ( [ вир1 ]; [ вир2] ;[ вир3 ] ) оператор;,
де вир1 вираз ініціалізації, звичайно використовується для встановлення початкового значення; це вираз присвоювання (необов'язковий параметр);
вир2 вираз умови , що визначає при якій умові цикл буде повторюватися (необов'язковий параметр);
вир3 вираз ітерації, що визначає крок зміни змінних, керуючих циклом після кожного виконання (необов'язковий параметр).
Цей оператор реалізується в такий спосіб:
спочатку виконується вираз ініціалізації ( ця нотація може бути виконана до оператора for );
обчислюється умовний вираз( якщо результат умовного виразу “істина” (не дорівнює нулю ), то виконується оператор циклу;
обчислюється вираз ітерації;
знову перевіряється умова;
як тільки умовний вираз стає рівним нулю “неістина”, керування передається оператору, що знаходиться за оператором циклу for .
Оскільки перевірка умови виконується перед циклом, то цикл може жодного разу не виконуватися, якщо умова відразу буде “неістина”.
Проілюструємо використання оператора циклу for для раніше розглянутого приклада 1.3:
// P1_7.CPP ( обчислення функції y = a * x * x - sin(x)
// с використанням оператора циклу for
#include <stdio .h>
#include <math.h>
void main ( )
{
float a, x, y;
a = 10.3 ;
for ( x = -1 ; x <= 1; x = x + 0.2 )
{
y = a * x * x - sin(x) ;
printf ( "x = % 4 f, y = % 6 f \n", x, y ) ;
}
}
В операторі for може використовуватися кілька змінних, керуючих циклом, а будь-які вирази можуть бути відсутними, наприклад :
int i;
for ( ; i < 4; i++)
або
int k, n, y;
for ( k = 0, n = 20; k <= n; k++, n-- )
y = k * n;
У цьому операторі використовується два вирази ініціалізації і два вирази ітерації. При виконанні такого оператору спочатку присвоюються значення змінним k = 0 і n = 20. Потім відбувається порівняння k <= n. Якщо ця умова має значення “істина”,то буде виконуватися тіло циклу, а потім вираз k++ і n--, якщо ж умова не виконується, тоді цикл припиняється.
Оператор циклу do звичайно використовується в тих випадках, коли тіло циклу повинне виконуватися хоча б один раз, і має наступну структуру запису:
do
{
оператор
}while (L); ,
де L умовний вираз.
Виконується оператор do наступним чином: спочатку здійснюється вхід у тіло циклу і виконується оператор (він може бути простий чи складний), після того перевіряється умова L і, якщо вона “істина” ( не дорівнює нулю), то цикл повторюється, а якщо “неістина ” здійснюється вихід з циклу. З використанням оператора циклу do приклад 1.3 буде мати вигляд:
// P1_8.CPP ( обчислення функції y = a * x * x - sin(x)
// с використанням оператора циклу do
#include <stdio .h>
#include <math.h>
void main ( )
{
float a, x, y;
a = 10.3 ;
x = -1 ;
do
{
y = a * x * x - sin ( x ) ;
printf ( " x = % 4 f, y = % 6 f \n ", x, y ) ;
x = x + 0.2;
}
while ( x <= 1 );
}
1.5 Контрольні питання
1. Які правила запису програми мовою С++ ?
2. Які дані обробляються за допомогою мови С++ ?
3. Як задаються типи даних у С++ ?
4. Що таке константа в С++, наведіть приклади констант?
5. Що називається змінною в С++?
6. Як забезпечується організація введення- виведення ?
7. Як організується форматований висновок результатів ?
8. Для чого потрібні оператори умовного і безумовного переходу і як вони працюють ?
9. Як працює оператор switch ?
10. Які оператори циклу ви знаєте, як працює оператор циклу for ?
11. Які особливості роботи оператора циклу do і while ?
1.6 Варіанти індивідуальних завдань
Для приведених нижче варіантів необхідно скласти програму обчислення значення функцій при різних значеннях аргументів, заданих інтервалом зміни і величиною кроку.
1.
2.
3.
а=5; b=3 ;
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
x і a змінюються одночасно.
16.
а - має початкове значення 0.1 і змінюється одночасно с x с кроком .
17.
18.
При якім значенні х функція буде найменшою.
19. Підрахувати скільки разів функція приймає негативне значення, якщо .
20. Увести координати 10 крапок на площині і визначити, у якій із чвертей більше всього крапок.
21. Увести п'ять наборів сторін трикутника а, b, c і визначити для яких сторін висота буде найбільшою.
Підказка: де
22. Увести координати п'яти крапок і визначити яка з них потрапить в окружність з радіусом R і координатами центра (а, в).
Підказка: рівняння окружності має вид:
23. Увести п'ять шестиразрядных цілих чисел і знайти для яких з них сума «лівих» трьох цифр більше суми «правих» трьох.
24. Підрахувати скільки разів функція
приймає негативне значення, якщо .
25. Обчислити функцію у вигляді формули
для кожного значення i.
2 РОЗВЯЗАННЯ ЗАДАЧ C ВИКОРИСТАННЯМ ОДНОВИМІРНИХ І ДВОВИМІРНИХ МАСИВІВ
При підготовці до роботи повторити способи опису одновимірних і двовимірних масивів, використання індексованих змінних при обробці даних, організацію введення і виведення масивів, використання покажчиків .
На відміну від задач, розглянутих у попередній лабораторній роботі, аргумент функції може бути заданий і іншим способом у вигляді довільного набору значень.
Приклад 2.1 Обчислити функцію y = axi2 sin xi, де x1=-1, x2=-0,93, x3=-0,49, x4=0, x5=1,13, x6=0,96, x7=1,75.
При розвязанні такої задачі кожне з перерахованих значень треба ввести в пам'ять комп'ютера, для чого буде потрібно відповідна кількість комірок. Такий довільний ряд однотипних значень, які мають одне загальне символічне ім'я (ідентифікатор), називається масивом. Окреме значення масиву називається його елементом, а місце розташування елементів у масиві визначається за допомогою його індексу. У пам'яті комп'ютера масив займає стільки комірок пам'яті, скільки в ньому елементів.
У схемі алгоритму розвязання задачі спочатку передбачається введення значень всіх елементів оброблюваного масиву x[n] (n =7 ). Число в дужках визначає кількість елементів масиву. Нумерація елементів масиву починається з 0 і закінчується n 1 . Далі введені елементи використовуються при обчисленні функції, шляхом вказівки індексу відповідного елемента.
Схема алгоритму розвязання цієї задачі і програма виглядають наступним чином:
//P2_1.CPP -обчислення значень функції
// використання одновимірного масиву
#include <iostream.h>
так
немає
#include <math.h>
void main( )
{
const int n =7;
float x[n];
int i;
float a, y;
// Введення масиву
cout<< "Введіть значення масиву:" <<endl;
for ( i=0; i < n; i++)
{
cout << "x [" << i << "] = ";
cin >> x [ i ] ;
cout << x [ i ] << endl;
}
a = 10.5;
// Обчислення функції
for ( i = 0; i < n; i++)
{
y = a*x [ i ] * x [ i ] sin ( x [ i ] )
. cout << "При значенні=" << x[i]
<< "y = " << y << endl;
}
}
При запису цього алгоритму у вигляді програми спочатку треба описати масив за допомогою оператора float x [n], ввести його значення в пам'ять комп'ютера, а потім робити необхідні обчислення.
У програмі, що реалізує даний алгоритм, для введення елементів масиву використовується оператор cin >> x [i] ;, перед цим оператором знаходиться підказка cout << "x [" << i << "] = "; і зазначен номер елемента x[i], значення якого треба ввести.
Особливість виконання оператора введення cin >> x[i] ; полягає в тому, що, зустрівши його в програмі, комп'ютер призупинить її виконання поки не буде введене значення елемента x[i] і натиснута клавіша Enter, після чого обробка програми буде продовжена. Зазначений оператор включений у цикл, реалізований за допомогою оператора for, і повторюваний n разів, для забезпечення введення всіх елементів масиву.
Оскільки в мові С++ індексація елементів масиву починається з нуля, то масив float x[7] (n =7 ) із семи елементів включає індексовані елементи x[0], x[1], x[2] … x[6] і при цьому x[0] звертання до першого елемента, x[1] звернення до другого елемента масиву і т.д. Пропонована програма використовує два цикли: один для введення елементів масиву, інший для обчислення функції. Ці операції можна виконати й в одному циклі, тоді програма буде мати вигляд:
// Р2_2.CPP введення елементів одновимірного масиву
// і обчислення функції здійснюється в одному циклі
#include < iostream.h>
#include < math.h>
float a, y ;
void main ( )
{
const int n =7;
float mas [ n ];
int i;
float a, y ;
a = 10.5;
for ( i = 0; i < n ; i++)
{
cout << "x [ " << i << "] = ";
cin >> x [ i ] ;
y = a * x[ i ]*x[ i ] - sin( x[ i ] );
cout << "При значенні =" << x[і] << " y= " << y << endl;
}
}
Приклад 2.2 Обробити відомість успішності групи студентів з 10 чоловік по програмуванню, підрахувавши середній бал групи і кількість відмінників.
Список оцінок представимо масивом МА[i] (i=0..9), і програма, що реалізує таку задачу, виглядає в такий спосіб :
// Р2_3.CPP використання одновимірних масивів
// Визначення середнього бала групи і кількості відмінників
#include < iostream.h >
#include < math.h >
void main ( )
{
const int n = 10; // розмірність масиву
float mas[n]; // опис одновимірного масиву
int i, k;
float s;
s = 0 ; // s - змінна для підсумовування оцінок групи
k = 0 ; // k - змінна для підрахунку кількості відмінників
for ( i=0; i < n; i++ )
{
cout << " mas [ " << i << "] = ";
cin >> mas [ i ] ;
cout << mas [ i ] << endl;
s = s + mas [ i ];
if ( mas[ i ] = = 5)
k =k+1;
}
cout << "Середній бал = " << s / float(n ) << endl;
cout << "Кількість відмінників =" << k<< endl;
}
У цій програмі змінна s служить для обчислення суми оцінок групи, а змінна k для підрахунку кількості відмінників. Перед обчисленням треба задати цим змінним початкового нульового значення. Оператор cout << " mas [ " << i << "] = "; усередині циклу виконує роль підказки про необхідність введення чергової оцінки, а наприкінці використовується для виведення результатів обчислення ( cout << "Середній бал"<< s / float (n) << endl; cout << "Кількість відмінників =" <<k<< endl;) .
Крім одновимірних масивів, тобто таких, де положення елемента визначається за допомогою одного індексу, у практиці розвязання задач часто застосовуються багатовимірні масиви. У них положення елемента визначається шляхом запису декількох індексів. Найбільш широке поширення одержали двовимірні масиви, які називаються матрицями. Матриці являють собою порядковий запис декількох одновимірних масивів, наприклад:
Місце розташування кожного елемента визначається за допомогою двох індексів номера рядка і номери стовпця, тобто порядкового номера в рядку.
Індекси таких масивів записуються в квадратних дужках. Наприклад, запис М[1] [2] вказує на елемент, що знаходиться в другому рядку і третьому стовпці, тобто маючий значення -20.5 (рахунок індексів починається з 0). Для перебору всіх елементів матриці при їхньому введенні-виведенні, а також при обробці в програмі варто передбачати організацію двох циклів: один для завдання значень індексу рядків, інший -індексу стовпців.
Приклад 2.3 До кожного елемента вищенаведеної матриці M додати число 10.
// Р2_4.CPP використання двовимірних масивів
// До кожного елемента матриці додати число 10.
#include < iostream.h >
void main ( )
{
const int n = 3; // кількість рядків матриці
const int m = 5; // кількість стовпців матриці
float M [ n] [m];
int i, k;
float s;
s = 10 ;
cout << " Введіть значення масиву:" << endl;
// Введення значень двовимірного масиву
for ( i = 0; i < n; i++)
for ( k = 0; k < m; k ++)
{
cout << " M [ " << i << "] = " << "[ " << k << ]" ;
cin >> M [ i ] [ k ];
cout << M [ i ] [ k ] << endl;
M [ i ] [ k ] = M [ i ] [ k ] + s ; // Можна M [ i ] [ k ] + = s ;
}
cout << "Нове значення матриці :" << endl;
// Виведення матриці в природному вигляді
for ( i = 0; i < n; i++)
{
cout << endl;
for ( k = 0; k < m; k++)
cout << M [ i ] [ k ] << " ";
}
}
У програмі при описі матриці в операторі float M[n][m]; вказується діапазон зміни двох індексів, перший з яких призначений для індексування рядків, другий стовпців.
При введенні, обробці і виведенні матриці для перебору всіх її елементів використовується два цикли, один із яких є вкладеним в іншій. Це дозволяє при кожнім значенні змінної i перебирати всі значення k.
Розглянута програма може бути скорочена шляхом об'єднання всіх трьох блоків циклу в один, але в такому випадку вона буде менш наочною.
2.3 Використання покажчиків
У мові С++ широко використовуються дані, що називаються покажчиками.
Покажчики це змінні, котрі містять адресу пам'яті, розподіленої для іншої змінної. Усі змінні, розглянуті до цього, зберігали якісь значення (дані). Ці дані могли бути різних типів: символьного, цілого, дійсного і т.д. При оголошенні змінної - покажчика необхідно вказати тип даних, адресу яких буде містити змінна, і ім'я покажчика з попередньою зірочкою.
Загальний формат опису покажчика наступний:
тип * ім'я;
де тип тип значень, на который буде вказувати покажчик;
ім'я ім'я змінної-покажчика;
* означає операцію над типом, що читається "покажчик" на тип.
Наведемо приклади визначень покажчиків:
int *pn; // покажчик на ціле значення;
float *pf1, *pf2 ; // два покажчики на дійсні значення;
Покажчики не прив'язують дані до якого-небудь визначеного імені змінної і можуть містити адреси будь-якого неіменованого значення. Існує адресна константа NULL , що означає "порожню" адресу.
У мові С++ знаходиться усього два оператори, що відносяться до покажчиків:
“&” оператор " адреса значення ";
“* “ оператор "значення за адресою".
Оператор "*" , використовуваний разом з покажчиками, витягає значення, на яке вказує змінна, розташована безпосередньо після нього.
Оператор "&" , використовуваний разом з покажчиками, повертає адресу змінної, розташованої безпосередньо після нього.
Покажчики можна оголосити одним з наступних способів:
<тип.> *ptr;
<тип> *ptr = <перемінна - покажчик>;
<тип> *ptr =&<ім'я змінної>; // адреса змінної
У програмі це може виглядати в такий спосіб:
int *ptx ,b ; float y; // оголошені перемінна - покажчик ptx і звичайні змінні b і y;
float *sp = &y; // покажчику sp привласнюється адреса змінної y
float *p = sp; // покажчику p привласнюється значення (адреса значення),
// яке міститься в змінній sp, тобто адреса змінної y.
При оголошенні покажчиків символ "*" може розташовуватися або перед ім'ям покажчика або записуватися відразу після оголошення типу покажчика і поширює свою дію тільки на одну змінну - покажчик, перед якою він знаходиться, наприклад:
long *pt; long* Uk; int * ki, x, h ; // оголошення описів
У разі потреби опису покажчика на комірку довільного типу, замість ідентифікатора типу записується слово void, наприклад:
void *p, *pt; // описані два покажчики на довільний тип даних
Перш ніж використовувати покажчик у програмі, йому обов'язково треба присвоїти адресу якого - небудь даного, тобто проініціалізувати, інакше можуть бути непередбачені результати.
Для доступу до значення змінної, адреса якої зберігається в покажчику, досить у відповідному операторі програми записати ім'я покажчика із символом "*" , наприклад:
int *p, *p1; // Оголошені два покажчики на комірку пам'яті int;
int x =12, y=5, m [7 ]; // Оголошені змінні x,y і масив m,
// змінні x,y ініціалізовані
p = &y; // Покажчику p привласнена адреса змінної y.
Тепер, якщо написати оператор виведення на екран у вигляді :
cout << "Адреса р " << p << "Значення по цій адресі= " <<*p; ,
тоді виведеться адреса комірки пам'яті, де записана змінна y і значення цієї змінної (тобто 5).
Використовуючи запис x = *p; , одержуємо x=5, тому що *p = y = 5; .
Змінити значення y можна таким чином:
y = 10; // чи *p = 10;
і виконавши операцію
*p= *p+5; // це рівнозначно операції y = y + 5; тобто y = 15.
При оголошенні покажчиків, їм потрібно привласнювати початкові значення ( ініціалізувати ), при цьому можна або привласнювати адресу об'єкта (змінної), або адресу конкретного місця пам'яті (масиву), або число 0 (нуль), наприклад:
int *pt = (char *) 0x00147; // Привласнюється адреса комірки
int *arrpt = new int [10]; // Визначається початкова адреса розміщення
// динамічного масиву
сhar *p = 0; // Ініціалізація нулем
Оскільки покажчики це спеціальні змінні, то в операціях з іншим покажчиками вони можуть використовуватися без символу "*", тобто без розкриття посилання, наприклад:
float *pt1, *pt2 , x=15, m[5];
pt1=&x;
pt2=pt1;
pt1 = m; // або pt1 = &m[0]; m це ім'я масиву, що
// розглядається як спеціальний покажчик константа.
// P2_5.CPP застосування покажчиків
#include < iostream.h >
int main ( )
{
int x = 10;
int *px = &x;
cout << " x =" << x << endl;
cout << "*px =" << *px << endl;
x* = 2; // або x = x*2;
cout << " Нове значення* px =" << *px << endl;
*px += 2; // або *px =*px + 2;
cout << " Нове значення* px=, тобто х=" << x << endl;
return 0;
}
Результат виконання програми:
x = 10
*px = 10
Нове значення *px = 20
Нове значення*px, тобто x = 22
Сам покажчик-змінна має свою адресу, тому буде справедливим
наступний запис:
int *pt1, *pt2;
pt1 = (int*) &pt2; // тут покажчику pt1 привласнюється адреса пам'яті,
// де розташована змінна pt2
Це має сенс у ситуації, коли :
int y,*pt1, *pt2 =&y;
pt1 = (int*) & pt2; .
Існують наступні обмеження на використання операції взяття адреси "&":
не можна визначати адресу константи ( оскільки їй не приділяється комірка пам'яті), тобто неприпустимий запис : vp = &345;
не можна визначати адресу результату арифметичного виразу, тому наступний запис невірний : vp = & (x + y); .
Для змінних покажчиків дозволені операції:
присвоювання;
інкремент і декремент;
додавання і віднімання;
порівняння покажчиків однакового типу.
Наприклад, демонстраційна програма з використанням змінних-покажчиків може мати вигляд:
//P2_6.CPP використання змінних- покажчиків
#include <iostream.h>
void main ( void )
{
int *ptr1 = (int*)100 ;
int *ptr2 = (int*) 200;
ptr1++;
ptr2 -= 10;
cout << "ptr1=" << ptr1 << endl;
cout << "ptr2=" << ptr2 << endl;
cout << "ptr2 - ptr1=" << ptr2 - ptr1 << endl;
}
Результат виконання програми :
ptr1 = 00000068
ptr2 = 000000A0
ptr2 - ptr1 = 14
У програмі операція ptr1++ збільшить адресу на 4 байта , оскільки дані типу int займають 4 байти , операція ptr2-=10 зменьшує адресу на 40 байтів. Адреси виводяться на екран в шістнадцятковому вигляді.
2.4 Використання масивів і покажчиків
У мові С++ масиви і покажчики зв'язані між собою. При оголошенні масиву у вигляді : int mas [20]; ім'я масиву mas визначається як покажчик-константа на перший (нульовий) елемент масиву, тобто на адресу першого елемента масиву &mas[0].
Для доступу до елементів масиву існує два способи:
використання індексу елемента масиву, наприклад, mas[2] або mas[i];
використання адресного виразу тобто виразу з покажчиком на
масив, наприклад, *( mas +2 ) чи *( mas+i ).
Ім'я масив-покажчик, можна записати в наступному вигляді:
int mas [20];
int *ptr1;
ptr1 = mas; // чи ptr1 = &mas[0];
Після оголошення масиву int mas [20]; вираз &mas[0] і mas є еквівалентними.
Для обнуління елементів оголошеного масиву досить ініціалізувати його перший елемент: int mas[0] = {0} ; При цьому першому елементу не обов'язково привласнювати значення 0. Якщо в оголошеному масиві ініціалізується трохи перших елементів, то інші ініціалізуються нулями.
Наприклад, у випадку коли float mas [10] ={ 12.2, 34.56 }; , останні вісім елементів одержать значення 0.
Глобальні масиви автоматично ініціалізуються двійковими нулями, у тому числі і символьні.
При оголошенні масивів можна використовувати одну з форм запису :
< тип > < ім'я > [n] // Оголошення одновимірного
// масиву з n елементів
< тип > < ім'я > [n] = { значення } // Значення елементів масиву
< тип > < ім'я > [ ] = { значення } // розділені комою
Наприклад:
float m[6];
float m[6] = { 3.4, 4.5, 5.6, 6.7, 8.9, 10.3 };
float m[ ] = { 3.45, 4.56, 5.67, 6.78 };
Двовимірні і багатовимірні масиви описуються аналогічним образом, тобто правомірний запис :
int mas [2][5] ={ 1, 2, 3, 4, 5,
10, 11, 13, 14, 25 };
int mas [2][5] ={ {1, 2, 3, 4, 5},
{10, 11, 13, 14, 25} };
int mas [ ][5] ={ 1, 2, 3, 4, 5,
10, 11, 13, 14, 25 }; .
При оголошенні одновимірних масивів їхній розмір можна не вказувати, якщо оголошений масив відразу ініціалізується.
В оголошенні багатовимірних масивів можна опускати кількість індексів тільки першого виміру при одночасній ініціалізації. Якщо під час оголошення масивів ініціалізація не проводиться , то кількість індексів треба вказувати завжди і скрізь.
Оскільки для масивів завжди в пам'яті приділяється суцільний блок комірок пам'яті, у яких розташовуються елементи, то адресу наступного елемента mas[1] можна вказати шляхом збільшення покажчика на 1, тобто якщо p = &mas[0] , тоді p=p + 1 або ( p += 1) а для i елемента масиву адреса може бути визначена як p + i; . При цьому автоматично виконується операція збільшення адреси з урахуванням типу масиву і кількості, що відводиться, байт для кожного його елемента, отже :
адреса х[і] = адреса x[0] + і*sizeof ( тип ); .
Якщо два покажчики р1 і р2 указують на елементи одного масиву, то до них застосовні операції відносини: == , != , < , <= , > , >= .
Наприклад, відношення вигляду р1 < р2 істинно, якщо р1 указує на більш ранній елемент, ніж р2 . Всякий покажчик можна порівняти з нулем.
Варто звернути увагу, що для покажчиків, що посилаються на елементи різних масивів, результат арифметичних операцій і відносин не визначений. В арифметиці з покажчиками можна використовувати адресу не існуючого "наступного за масивом " елемента. Крім того, до покажчика можна додати деяке ціле значення, наприклад можна записати:
р + n ; ,
де n ціле значення, а р покажчик.
Цей вираз визначає область об'єкта, що займає n -те місце після об'єкта, на який указує р, при цьому n автоматично збільшується на коефіцієнт,що дорівнює відповідній довжині об'єкта. Наприклад , якщо int займає 4 байти , те цей коефіцієнт дорівнює чотирьом.
Допускаються також gjhsdyzyyz покажчиків, що вказують на елементи одного масиву.
Наприклад, якщо р1< p2, те р2 - р1+1 це число елементів масиву від р1 до р2 включно.
Таким чином, з покажчиками допускаються наступні операції :
присвоювання значення одного покажчика іншому;
додавання і вирахування покажчиків і даного цілого типу ( р+5 );
порівняння двох покажчиків, що посилаються на елементи одного масиву;
присвоювання покажчику нуля і порівняння з нулем.
Інші операції з покажчиками заборонені.
Для покажчика дозволяються вирази вигляду:
р1 = mas; або р++ ,
тут р покажчик , mas масив.
Розглянемо демонстраційні приклади програм роботи з покажчиками.
Приклад 2.4 Обчислити середнє значення позитивних елементів одновимірного масиву.
Наведемо кілька варіантів програмної реалізації цієї задачі.
// P2_7.CPP обчислення середнього значення
// додатних елементів масиву
// програма без використання покажчиків
#include <iostream.h>
main( )
{
const int n = 5;
float mas[n], s = 0;
int kol = 0;
for( int i = 0; i < n; i++)
{
cout << "Введіть" << і << "елемент mas" << endl;
cin >> mas[ i ];
if ( mas[ i ] > 0 )
{
s += mas[ i ];
kol ++;
}
}
s/ = kol;
cout << "s=" << s << endl;
return 0;
}
Використовуючи ім'я масиву як покажчик на початок масиву (перший елемент), цю програму можна переписати в такий спосіб:
// P2_8.CPP обчислення середнього значення
// додатних елементів масиву
// використання імені масиву як покажчика на його початок
#include < iostream.h>
main ( )
{
const int n = 5;
float mas[n], s = 0;
int kol = 0;
for ( int i=0; i < n; i++)
{
cout << "Введіть" << і << "елемент mas" << endl;
cin >> *( mas+i);
if(* ( mas+i ) > 0 )
{
s+= *(mas+i);
kol++;
}
}
s/=kol;
cout << "s=" << s << endl;
return 0;
}
Якщо описати покажчик, зв'язати його з масивом (адресувати на початок масиву),то використовуючи арифметику покажчиків, можна написати цю програму у вигляді:
// P2_9. CPP обчислення середнього значення
// додатних елементів масиву
// використання арифметики покажчиків
#include < iostream.h>
main ( )
{
int kol = 0;
const int n = 5;
float mas[n], s = 0;
float *pm = mas; // припустимий запис pm=&mas[0]
for ( int і = 0; і < n; і++)
{
cout <<"Введіть"<< і <<"елемент mas" << endl;
cin >> *pm++;
cout << mas[i] << endl;
if (mas[i] > 0)
{
s+=mas[i];
kol++;
}
}
s/= kol;
cout << "s=" << s << endl;
return 0;
}
У наведеній програмі при введенні масиву використовувався покажчик *pm , а при роботі з ним ім'я масиву з індексом. Якби при роботі з масивом використовувався покажчик *pm , то результат був би не вірним. Це пояснюється тим, що покажчик *pm в операціях введення він збільшує свою адресу ( pm++) після введення чергового елемента масиву і надалі вказує ще не введений елемент.
Наведемо ще один варіант програмної реалізації цієї ж задачі.
// P2_10.СРР обчислення середнього значення
// додатних елементів масиву
// використання покажчиків
#include < iostream.h >
main ( )
{
const int n = 5;
float mas[n], s = 0;
float *pm = mas; // *pm=&mas[0]
int kol = 0;
for ( int i = 0 ; i < n ; i++)
{
cin >> *pm;
cout << "Введіть" << і << "елемент mas" << endl;
if (*pm > 0)
{
s += *pm;
kol ++;
pm ++;
}
}
s/= kol;
cout << "s=" << s << endl;
return 0;
}
Приклад 2.5. Скласти програму сортування одновимірного масиву за
зменшенням методом вставки.
// P2_11.CPP сортування методом вставки (за зменшенням)
// застосування покажчиків
#include < iostream.h >
#include < conio.h >
main ( )
{
int stc, mas [6], i, j;
int *pmas;
pmas = mas;
cout << "Введіть 6 елементів масиву" << endl;
for ( i = 0; i < 6; i++) cin >>*pmas++;
// Наступний оператор знову встановлює покажчик на початок масиву
// (інакше він буде вказувати на наступну за масивом адресу)
pmas = mas;
for ( i =1; i < 6; i++)
{
stc = *(pmas + i);
j = i - 1;
while ( j >= 0 && stc > *(pmas+j))
{
*(pmas+j+1) = *(pmas+j);
j - - ;
}
*(pmas+j+1) = stc;
}
cout << "Результат" << endl;
for ( i = 0; i < 6; i++)
cout << i << " елемент " << *(pmas + i ) << endl;
// Можна використовувати і таку конструкцію оператора
// cout << i << " елемент " << * pmas++ << endl;
getch ( ); // Для затримки екрана виведення результату
return 0;
}
2.5 Масиви покажчиків
Як і інші змінні, покажчики можна групувати в масиви, кожен елемент якого містить адресу рядка масиву даних у пам'яті. У такий спосіб можна зберігати дані з "рваними" краями. Цей масив схожий на двовимірну таблицю з одним виключенням: усі рядки в такому масиві можуть мати різну довжину. При збереженні рядків це дозволяє заощаджувати пам'ять, а при виконанні сортування рядків, вона виконується значно швидше, тому що змінююється тільки покажчики, а не значення рядків.
fio
(0) |
-> |
П |
Е |
Т |
Р |
О |
В |
\0 |
|
(1) |
-> |
І |
В |
А |
Н |
О |
В |
\0 |
|
(2) |
-> |
К |
У |
Ц |
И |
Й |
\0 |
||
(3) |
-> |
В |
А |
Р |
І |
Ч |
\0 |
||
(4) |
-> |
Ю |
Ш |
К |
О |
\0 |
|||
(5) |
-> |
П |
Л |
Ю |
Щ |
\0 |
Приведемо програму реалізуючу виведення подібної інформації з використанням масиву покажчиків.
// P2_11.CPP
#include <iostream.h>
main ( )
{
char *fio [ ] = { "Петров",
"Іванов" ,
"Куций",
"Варич",
"Юшко",
"Плющ " };
int str;
for ( str = 0; str <= 5; str++)
cout << " stroka " <<( str +1 ) << ” = ” << *( fio+str ) << endl;
return 0;
}
Особливістю масиву покажчиків є те, що кожен з цих покажчиків елементів масиву може вказувати на масив довільної довжини. Так двовимірний масив чисел можна записати як матрицю, і як одновимірний масив покажчиків, наприклад: int matr[5][7]; чи int *pmt [5]; .
При цьому двовимірний масив розглядається як одновимірний масив рядків, кожен елемент якого це теж масив стовпців, тобто масив масивів, тому індексування елементів матриці записується у вигляді mas [i][j]. Якщо двовимірний масив описаний за допомогою масиву покажчиків, то доступ до mas [i][j] елемента може здійснюватися одним зі способів:
* ( pm[i]+j ) або *( *( pm+i )+j ) .
Приклад 2.6 До елементів матриці, що має парні значення, додати число і вивести отриману матрицю в природному вигляді.
Перший варіант програмної реалізації матриця описується явним способом і робота ведеться з її елементами.
// P2_12.CPP робота ведеться без покажчиків.
#include < iostream.h >
void main( )
{
int mat [2][3];
int і, j;
cout << " Введіть матрицю "<< endl;
for ( i = 0; i < 2; i++)
for ( j = 0; j < 3; j++)
cin >> mat [i] [j] ;
// Обробка і виведення матриці
cout << " Матриця mat " << endl;
for ( i = 0; i < 2; i++)
{
for ( j = 0; j< 3; j++)
{
if ( ( mat [i][j] /2 )*2 == mat[i][j])
mat[i][j] = mat[i][j] + 5;
cout << mat [i][j] << " ";
}
cout << endl; // Переведення рядка при виведенні матриці
}
}
Другий варіант програмної реалізації матриця описана як масив покажчиків.
//P2_13.CPP матриця описана як масив покажчиків:
#include < iostream.h >
main ( )
{
int і, j, *pm[2];
cout << "Введіть матрицю "<< endl;
for ( i = 0; i < 2; i++)
for ( j = 0; j < 3; j++)
cin >> *( pm[i] + j );
cout << " Матриця МАТ "<< endl;
for ( i = 0; i < 2; i++)
{
for ( j = 0; j < 3; j++)
{
if ( *(pm[i] + j) / 2*2 == *( pm[i] + j ) )
*( pm [i] + j ) += 10;
cout << *( pm [i] + j) << " ";
}
cout << endl;
}
return 0;
}
У розглянутій програмі для виведення матриці можна використовувати інший вигляд оператора :
сout << ( (j == 0) ? '\t':' ') << *( pm[i]+j ) << ( (j == 2) ? '\n':' ') ;
Ім'я двовимірної матриці є покажчиком-константою на масив покажчиків-констант, кожний з яких указує на початок відповідної рядка матриці, наприклад для матриці mat [2] [2] маємо :
mat [0] покажчик-константа на нульовий рядок матриці;
mat [1] покажчик-константа на перший рядок матриці;
mat [2] покажчик-константа на другий рядок матриці;
тобто: mat[0] == &mat[0][0];
mat[1] == &mat[1][0];
mat[2] == &mat[2][0];
Виведення матриці можна реалізувати в такий спосіб:
cout << mat [i] [j];
cout << *( mat [i] +j );
cout << *(* (mat +i )+j );
У С++ можна описати змінну, що має тип "покажчик на покажчик". Ознакою такого типу є повторення символу "*" при описі змінної, наприклад int ** pmt; при цьому пам'ять для такої змінної не виділяється. Її треба привести до відповідного масиву. При описі покажчик на покажчик можна ініціалізувати, наприклад :
int x = 20;
int *px1 = &x;
int** px2 = &px1;
int ***px3 = &px2;
Доступ до змінної x тепер можна здійснити одним із трьох способів: *px1; **px2; ***px3; .
Для доступу до пам'яті через покажчики на покажчики можна використовувати як індекси так і символи "*", наприклад, еквівалентними будуть посилання на змінну x:
px1 [0] *px1;
px2 [0][0] **px2;
px3 [0][0][0] ***px3;
1. Що таке масив?
2. Як здійснюється опис масивів у програмі?
3. Як вибирається елемент масиву з пам'яті?
4. Які ще оператори мови C++ можна використовувати для введення елементів масиву в пам'ять комп'ютера?
5. Скільки циклів треба використовувати для введення, виведення і перебору елементів матриці?
6. Як звернутися до довільного елемента масиву?
7. Які обмеження існують у C++ на розмір і розмірність масивів?
8. Як вивести на друк матрицю в природному вигляді?
У запропонованих нижче варіантах завдань конкретні значення масивів задаються довільно.
1. Обчислити добуток і кількість негативних елементів масиву М(15).
2. Знайти максимальний елемент масиву Х(12) і його індекс.
3. Усі відємні елементи масиву М(15) записати в масив МО, а додатні у МР. Вивести отримані масиви на екран.
4. Знайти мінімальний елемент масиву Х(17) і його індекс.
5. Група учнів з 20 чоловік здавала іспит. Вивести порядкові номери учнів, що одержали “5” і “4”.
6. Обчислити суму і кількість парних елементів масиву Х(15).
7. Відсортувати елементи масиву М(17) за зменшенням значень.
8. Усі негативні елементи масиву H(15) розділити на його мінімальний елемент.
9. Елементи масиву Х(15), що мають непарні значення, записати в масив Х1, а парні у масив Х2.
10. Відсортувати елементи масиву Y(20) за зростанням.
11. Всі елементи масиву М(15), що знаходяться раніш його мінімального елемента, записати в масив М1, а інші у М2.
12. Обчислити і знайти максимальне значення цієї функції, якщо a = 10,5; а хi масив чисел, що має 10 значень.
13. Знайти мінімальний елемент матриці K(3,5) і його індекс.
14. Всі елементи матриці М(4,5) з непарними значеннями замінити на 1, а з парними на 0.
15. Усі відємні елементи матриці Р(3,4) записати в масив РО, а додатні у масив РР.
16. Всі елементи матриці Matr(3,5), що мають непарні значення, записати в масив М1, а парні у масив М2.
17. Задано два масиви X(10) і Y(10), обчислити Z( i,j) = Xi+Yj, де j,j=10..1.
18. Знайти максимальний елемент головної діагоналі матриці Х (5,5).
19. Обчислити кількість негативних елементів, що знаходиться вище головної діагоналі матриці М (5,5).
20. Знайти максимальний елемент у третьому рядку матриці Р(5,5) і його індекс.
21. Поміняти місцями елементи першого і третього рядка матриці Q(3,5).
22. Знайти мінімальний елемент і його індекс серед елементів, що знаходиться вище головної діагоналі матриці К (5,5).
23. Поміняти місцями елементи першого і другого стовпців матриці С(5,4).
24. Розділити всі елементи матриці Р(4,4) на суму позитивних елементів її головної діагоналі.
25. Помножити всі елементи матриці М(5,5) на суму позитивних елементів, що знаходяться на її головній діагоналі.
3.2 Методичні рекомендації з організації самостійної
роботи студентів
При підготовці до даної лабораторної роботи рекомендується повторити типи даних, звернувши увагу на символьний тип, способи завдання рядків і на застосування структурних типів даних для вирішування практичних задач .
В усіх попередніх роботах використовувалися числові типи даних. Однак ефективність мови С++ багато в чому визначається наявністю в ньому розвитих засобів для обробки символьної інформації. У стандартній бібліотеці С++ передбачено багато функцій , що виконують прості дії із символьними даними. Тому ця мова найкраще підходить для системної роботи: написання компіляторів, інтерпретаторів, операційних систем, редакторів тексту і т.п.
У мові С++ розрізняють символьні константи і рядки.
Символьна константа це одиночний символ, укладений в апострофи. Керуючі послідовності розглядаються як одиночний символ, наприклад: " " проміжок, "а " літера а, " \ " зворотна коса риса.
Тип char використовується для зображення символу. Значенням об'єкта типу char є код у наборі символів персонального комп'ютера, що відповідає даному символу. Тип char за замовчуванням інтерпретується як однобайтова ціла величина зі знаком (діапазон значень перемінної від -128 до 127). Змінна типу unsigned char може запам'ятовувати значення в діапазоні від 0 до 255.
Рядок це послідовність символів, укладена в лапки ("), наприклад: "Це рядок". Він зберігається в послідовній області пам'яті, у кінець якої компілятором додається нульовий символ ("\0"), що подається керуючою послідовністю "\0" і є символьним масивом. Рядки мають тип char [ ]. Число елементів масиву дорівнює числу символів у рядку плюс 1, тому що нульовий символ також є елементом масиву. Рядки можуть розташовуватися на декількох рядках. У цьому випадку ставиться зворотна дробова риса і натискається клавіша ENTER. Зворотна риса із символом нового рядка ігнорується компілятором, і наступний рядок вважається продовженням поточного.
3.2.1 Організація символьного введення - виведення
Функції символьного введення - виведення мови С++ є базовими функціями, необхідними для написання могутніх підпрограм введення-виведення даних.
Мова С++ сприймає все введення-виведення як потоки символів. Потік символів може бути організований: із клавіатури, файлу, модему і т.д. Операційна система забезпечує стикування пристроїв, а С++ може використовувати ті самі функції для введення - виведення, наприклад, як із клавіатури, так і з модему. От чому таке велике значення приділяється обробці символьних типів даних. Для обслуговування операцій над рядками використовується файл <string.h> . При організації введення-виведення в мові С++ завжди передбачається, що введення буде здійснюватися з stdin, що означає стандартний пристрій введення (звичайно клавіатура), а виведення здійснюється на стандартний пристрій виведення (звичайно дисплей) з ім'ям stdout. Ці потоки можна перепризначити на роздрук ім'я stdprn, послідовний порт ім'я stdaux, повідомлення про помилки ім'я stderr. Оператор cout здійснює виведення на екран тільки тому, що більшість комп'ютерів за замовчуванням stdout направляє виведення на екран, а оператор cin здійснює введення з клавіатури за тою же причиною, тому що клавіатура є стандартним пристроєм введення (stdin).
Розглянемо порядок дій при перепризначенні потоку виведення даних на принтер :
підключення файлу заголовка ofstream.h ;
виконання перепризначення виведення на принтер за допомогою операторів
ofstream prn ("PRN");
prn << " Виведення до роздруку повідомлення "<< endl;
prn << name1 << name2 ... <<endl;
Такий порядок дій застосовується при компіляції як задача DOS і нижче приведена його програмна реалізація .
Приклад 3.1 Вивести дані (прізвище й ім'я) на принтер.
// P3_1.СPP виведення прізвища й імені на принтер
#include < fstream.h>
main ( )
{
char fio [15];
char name [10];
cout << "Введіть прізвище ";
cin >> fio;
cout << "Введіть ім'я ";
cin >> name;
// Посилка імен fio і name на принтер
ofstream prn ("PRN");
prn << " Виведення імені і прізвища " << endl;
prn << name << fio << endl;
return 0;
}
Для організації символьного введення - виведення використовуються функції буферизированого (get ( ) і put ( )) і небуферизированого (getch ( ) і (putch ( )) введення виведення, формати цих функцій наступні:
device . get (char_var);
device . put (char_var); ,
де device може бути будь-яким стандартним пристроєм введеннявиведення.
Як видно з форматів функцій вони вводять або виводять по одному символу зі стандартних пристроїв. Функція get( ) припиняє виконання програми, сприймає один символ, що попадає спочатку в буфер і після натискання ENTER передає вміст буфера в програму. Функція getch( ) при одержанні символу, що вводиться, не виводить його на екран. Для відображення їх на екрані використовують функцію getche ( ). У функціях get( ) і put ( ) може бути перепризначений пристрій введення - виведення. Так для відкриття модему як пристрою введення - виведення і читання з нього треба використовувати заголовний файл ifstream.
Приклад 3.2 Скласти програму, що реалізує введення п'яти символів і збереження їх у вигляді масиву .
// P3_2.CPP робота з масивами символів
// Використання функції getch( ) і put ( )
#include < fstream.h>
#include < conio.h >
main ( )
{
int str;
char slovo [5];
cout << "Введіть 5 символів " << endl;
for ( str = 0; str < 5; str++)
{
slovo [str] = getch ( )
}
// Посилка масиву символів на принтер
ofstream prn ("PRN");
prn << " Виведення масиву символів” << endl;
for( str = 0; str < 5 ; str++)
{
prn.put ( slovo [str] );
}
return 0;
}
У цій програмі використовується файл заголовка <conio.h>, у якому описані getch ( ) і put( ) і програма буде працювати після компіляції її в DOS.
3.2.2 Рядки як символьні масиви
У мові Сі і ранніх версіях мови С++ рядки розглядалися як символьні масиви і вся робота з ними ґрунтувалася на використанні цих масивів. Розроблена бібліотека функцій <string.h> містить могутні засоби для роботи зі строковими масивами .
Для опису рядка використовуються звичайні засоби опису масивів, наприклад: char str [25];. Індексування такого масиву, як і будь-якого іншого, починається з нуля. Символьні послідовності, розділені тільки проміжками, розглядаються як один рядок, тобто запис:
" У той рік осіння
погода"
ідентична рядку " У той рік осіння погода".
Усі рядки, у тому числі й ідентичні, у програмі розглядаються як різні об'єкти. Адреса першого символу рядка може використовуватися по-різному:
якщо рядок застосовується при ініціалізації масиву типу char, адреса його першого елемента стає синонімом імені масиву. Наприклад, ідентичними є наступні описи масиву:
char st [] = "Слово";
char st [6] = "Слово";
char st [6] = {'С' 'л' 'о' 'в' 'о' '\0'};
якщо рядок використовується для ініціалізації покажчика типу char*, адреса першого символу рядка буде початковим значенням покажчика, наприклад:
char *pst = "Слово"; ,
тут описується змінна - покажчик pst , що одержує початкове значення, рівне адресі першого елемента (символ С);
якщо рядок використовується у виразі (там, де дозволяється застосовувати покажчик), то компілятор підставляє у вираз рядка адресу його першого символу, наприклад:
char *pst;
pst = " Перший символ"; ,
тут pst одержує адресу букви "П", тобто при виконанні операції присвоювання в комірку пам'яті, відведену для покажчика pst, записується не масив символів, а тільки покажчик на його початок, тобто адреса першого символу рядка.
При описі символьного масиву, його ім'я не змінна, а покажчик-константа на початок рядка. Оскільки для константи не приділяється адреса в пам'яті, то її не можна використовувати в деяких операціях адресної арифметики, наприклад, не можна здійснювати операцію присвоювання вигляду:
char st [20];
st = " Петров"; // запис невірний, тому що не можна змінити значення st
Використання елементів масиву здійснюється через індекси або через покажчики. Для доступу до будь-якого символу рядка використовується індекс масиву char, наприклад, якщо описана змінна char str[3], то третім елементом масиву можна скористатися, записавши: str[3] або *(str+3).
При роботі з елементами масивів рядків, тобто двовимірним масивом, варто використовувати або індекси масиву, або індекси покажчиків, наприклад, якщо описаний список прізвищ
char spis [5] [15]; ,
то для використання символу масиву варто записати:
spis [i] [j] або *(spis [i] + j).
Аналогічно при оголошенні масивів покажчиків char *str [5] (указує на 5 елементів, кожний з який указує на рядок), а доступ до символу рядка можна здійснити, записавши *(str [i]+j).
3.2.3 Введення-виведення символьних масивів
Рядки можна вводити різними способами, найбільш розповсюдженими з яких є:
введення шляхом ініціалізації при оголошенні строкових масивів:
char st [5] = " Стіл";
char st [] = " Стіл";
char *pst = " Стіл";
у цьому випадку двовимірні масиви можна ініціалізувати одним з наступних засобів:
char str [5] [20] = {"Іванов И.И. ", "Сидоров С.С. ", . . . ,};
char str [ ] [20] = {"Іванов И.И. ", "Сидоров С.С. ", . . . ,};
char *pst [5] = {"Іванов И.И. ", "Сидоров С.С. ", . . . ,};
char *pst [ ] = {"Іванов И.И. ", "Сидоров С.С. ", . . . ,};
введення за допомогою оператора cin >> , якщо в рядку немає проміжків, тому що символ проміжок є роздільником вводу даних, наприклад:
char st [5]; cin >> st;
char *pst; cin >> *pst
char str [5] [20]; cin >> str [i];
char *pst [5]; cin >> ( pst [i] );
посимвольне уведення за допомогою функції get( ), наприклад get(st[i]);
за допомогою функції cin.get (str [i], size, endl) ; ,
де size - кількість символів, що читаються;
уведення за допомогою функції cin.getline ( str [i], sizeof ( str [i] ) ); ,
де sizeof( ) - функція визначення розміру рядка.
Виводити строкові дані можна використовуючи наступні записи:
cout << st;
printf ( “% s”,st ); // або ( sprintf )
puts ( st ); cout . write ( st , size ); і ін.
Приклад 3.3 Список рядків ( прізвища і ініціали Ф.И.О.) оголошений як масив покажчиків. Скласти програму , що реалізує введення масиву по рядках і посимвольне виведення цього масиву.
// P3_3.СРР список рядків оголошений як масив покажчиків
#include <stdio.h>
void main (void)
{
char *psp[ ] = { "Авдєєв А.А.'',
"Петров П.П.",
"Лисиця Л.Л. ",
NULL };
char **ptr =psp;
// Уведення масиву по рядках
while (*ptr)
puts (*ptr++);
ptr=psp;
// Виведення цього масиву посимвольне
while (*ptr)
{
while (**ptr)
{ putchar(**ptr); (*ptr)++; }
ptr++
}
}
Під час використання заголовного файлу stdio.h можна також застосувати, наприклад, такі функції:
для введення рядків для виведення рядків
puts(st) ; і printf(%s, st);
gets( st); cout.width(w);
scanf (% s,st) ; cout.precision (d);
setw(w);
setprecision(d);
3.2.4 Основні функції обробки символьних типів
У ранніх версіях С++ рядки розглядалися як символьні масиви і робота з ними ґрунтувалася на використанні цих масивів. Розроблена бібліотека функцій <string.h> містить могутні засоби для роботи зі строковими масивами. Згодом була розроблена стандартна бібліотека шаблонів Standard Template Library (STL) , що надає ще більш могутні засоби роботи з рядками, об'єднані в клас <string>. Цей клас включається як заголовний файл , тобто:
#include <string> // без літери h
Для обробки символьних типів даних бібліотека функцій <string.h> має велику кількість вбудованих функцій, що збільшують продуктивність праці програмістів і скорочують час на розробку програм. Ця бібліотека містить такі функції, як наприклад:
функції перевірки символів;
функції перетворення символів;
функції перевірки рядків;
функції маніпулювання рядками.
Усі ці функції приводяться у вигляді списків, згрупованих по їх розташуванню в заголовних файлах. Найчастіше приводяться прототипи функцій, що описують, яким образом використовувати функції в програмах.
Розглянемо прототипи, короткий опис дій і методику використання функцій, які частіше використовуються:
Копіювання рядків
char strcpy (s, *st); копіює байти рядка st у рядок s, (включаючи "\0"; повертає s), наприклад:
char str [50];
strcpy (str, "Сьогодні гарна погода ");
char *strdup (const char *str); копіює рядок str і повертає
покажчик на рядок копію, наприклад:
char *st1 = " Прийшла весна";
char *st2;
st2= strdup (st1); // Копіюється st1 у st2
char * strnсpy (char *st1,const char *st2, int n); копіює n символів з рядка st2 у st1, рядок st1 повинний бути більше чи дорівнювати st2, інакше виникне помилка, наприклад:
char st1[]= "Паскаль ";
char st2[] = "Привіт з далека ";
strnсpy (st1,st2,3); // Тепер у st1 "Прикаль"
Конкатенація слів
char *strcat (char *st1, const char *st2); поєднує st1 і st2 і повертає st1, наприклад:
char string [100];
strcpy (string, "Borland ");
strcat (string, " C++5"); ,
получаємо рядок string = "Borland C++ 5" ;
char *strncat (char *st1, const char * st2, int n); додає до рядка st1 n символів рядка st2 і повертає в st1, наприклад :
сhаr st1 [90] = "Привіт " ;
char st2 [50] = " Сашко і Маша";
strncat (st1, st2, 5);
st1 ="Привіт Сашко ".
Порівняння рядків
int strcmp ( char *st1, char *st2); - порівнює рядки st1 і st2 і повертає цілу величину, рівну:
< 0 якщо st1 < st2;
= 0 якщо st1 = st2;
> 0 якщо st1 > st2; ,
наприклад:
char st1[] = "Слово " ;
char st2 [] = "слово";
int k;
k = strcmp (st1, st2); // k < 0;
int stricmp (const char *st1, const char *st2); виконує порівняння рядків не зважаючи на регістр символів; повертає цілу величину як і в попередньому випадку (див. функцію strcmp() ), наприклад:
char st1[] = "Слово " ;
char st2 [] = "слово";
int k;
k = stricmp (st1, st2); k=0;
int strncmp (char *st1, char *st2, int n); виконує порівняння рядків c заданою кількістю символів n у st1 і st2 і повертає цілу величину:
< 0 якщо st1 < st2;
= 0 якщо st1 = st2;
> 0 якщо st1 > st2;
char *strnicmp (char *st1, char *st2, int n); виконує порівняння рядків c заданою кількістю символів n у st1 і st2, не зважаючи на регістр і повертає цілу величину як і в попередньому випадку.
Перетворення символів рядка
char *strlwr (char *st); перетворить символи рядка st верхнього
регістра в символи нижнього регістра, інші символи не зачіпаються,
Наприклад:
char st [i] =" Привіт Маша';
strlwr (st); // тепер st = "привіт маша".
char *strupr (char *st); перетворить символи рядка st нижнього регістра в символи верхнього регістра, інші символи не зачіпаються;
char *strrev (char *st); записує символи в рядку st у зворотному порядку (реверсує рядок), наприклад:
char st [] =" Hello";
strrev (st); // тепер st = "olleН ".
char *strchr (char *st , int c); визначає перше входження символу c у рядок st; повертає покажчик на символ у рядку st, що відповідає введеному зразку, наприклад:
сhаr st [90] = " Borland C++ 5 "
char *spt;
spt = strchr (st , '+');
// Тепер покажчик spt указує на підрядок "++5" рядка st.
char *strrchr (char *st, int c); знаходить останнє входження символу c у рядок st; якщо символ c у рядку не виявлений повертає 0, інакше повертає покажчик на останній символ у рядку st, що відповідає заданому зразку, наприклад:
char st [80] = "Borland C++5";
char *spt;
spt = strrchr (st , '+');
// Тепер покажчик spt указує на підрядок "+5" рядка st.
Пошук підрядка в рядку
strspn (const char *st1, const char *st2 ); повертає кількість символів від початку рядка st1, що збігаються із символами рядка st2, де б вони не знаходилися в st2, наприклад:
char st1 [] = "Borland C++5";
char st2 [] = " narlBod ";
int k;
k = strspn (st1, st2); // k=8
У цьому випадку змінна k одержує значення рівне 8, тому що перші 8 символів рядка містилися в st1 (включаючи символ проміжок).
char *strstr (const char *st1,const char *st2); функція шукає в рядку st1 перше входження st2 і повертає покажчик на перший символ, знайдений у st1 з підрядка st2; якщо рядок st2 не виявлена в st1 - функція повертає 0, наприклад:
char st1 [] = "Привіт друг, йдемо в кіно " ;
char st2 [] = "друг ';
char*spt;
spt = strstr (st1, st2);
Результат виконання:
spt = " друг, йдемо в кіно".
У разі потреби визначення останнього входження, треба спочатку реверсувати рядок за допомогою функції strrev.
char *strtok ( char *st, const char *dlm); - розбивка рядка на лексеми ( сегменти ), обмежені символами включеними до складу параметра dlm. Цей параметр може містити будь-яку кількість різних обмежників ознак границь лексем; після виділення лексеми в рядок st міститься символ '\0'.
Наступні виклики функції strtok() повинні бути. с першим аргументом NULL. Вони будуть повертати покажчик на інші , наявні в st лексеми. Щораз після завершення виділення лексем у її кінці замість розділового символу міститься символ '\0'. Після того, як у рядку не залишиться ні однієї лексеми, функція повертає NULL . Для збереження вихідного рядка її треба записати в резервну змінну. Цю функцію зручно використовувати для розбивки речення на слова або будь-які інші сегменти. Розглянемо приклад програми з використанням strtok():
Приклад 3.4 Увести речення, розбити його на слова з виведенням порядкового номера слова і підрахунком символів у кожнім слові:
//P3_4.CPP застосування функції strtok( ).
// визначення порядкового номера слова в реченні і
// підрахунок символів у кожнім слові
#include <string.h>
#include <iostream.h>
void main (void)
{
char *tk, *spt =", .!";
char st[] = "Сашко, нехай завжди буде солнце!";
cout << st << endl;
int i = 1;
tk = strtok (st, spt);
while (tk!= NULL)
{
cout << i << " слово-" << tk << " містить " <<
strlen(tk) << "символів" << endl;
tk = strtok (NULL,spt);
i++;
}
}
Для видалення з рядка підрядка або символу з заданої позиції в мові С++ немає спеціальної функції, однак можна написати свою, наприклад:
void del (char *st, int k, int n);
{
for ( int i = k; i < strlen(st); i++)
st[i] = st [i +n ];
st [i] ='\0'; // Запис '\0' у кінець нового рядка
}
де st вихідний рядок (покажчик на неї);
n кількість символів у підрядку що видаляється ;
k позиція, з якої треба видалити підрядок.
Нижче наведений приклад, що ілюструє реалізацію цієї програми
Приклад 3.5 Скласти програму видалення підрядка в n символів з k - ой позиції в рядку.
//P3_5.CPP ( видалення підрядка
#include <iostream.h>
#include <string.h>
const int n = 50;
const int m = 5;
void del(char *st, int, int);
void main()
{
char st [n], st1 [m];
cout << "Введіть рядок"<< endl;
cin. getline(st,n);
cout << "Введіть підрядок"<< endl;
cin >> st1;
if(strstr (st,st1)!=NULL)
{
del(st, strstr (st,st1) - st, strlen ( st1) );
cout << st << endl;
}
}
void del(char *st,int k,int n)
{
for( int i = k ; i < strlen ( st ); i++)
st[i] = st[i+n];
st[i] = '\0';
}
void* memchr (const void *st, int s ,int n); функція шукає символ "s" у рядку *st довжиною n байт, тобто в блоці пам'яті, на який указує покажчик st. Якщо символ s знайдений, функція повертає покажчик на цей символ, у противному випадку повертає NULL.
void* memcmp (const void *st, const void * s , n); і
void* memicmp (const void *st, const void * s ,int count); функції порівнюють n байт із двох буферів на її початок яких указують s1 і s2.
Функція повертає значення
< 0 якщо s1 < s2;
=0 якщо s1 = s2;
>0 якщо s1 > s2;
char *strset (char *st, int ch); функція заповнює рядок st символом ch і повертає покажчик на отриманий рядок.
Функції перетворення рядків у числа і чисел у рядки
Ці функції знаходяться у файлі <stdlib.h>
int atoi (const char *s); перетворить рядок s у число типу int. Повертається отримане число.Число 0, якщо зустрінеться символ, що не може бути перетворений. Рядок повинний містити коректне число, наприклад "2345", і мати наступну структуру:
[ проміжки ] [знак числа] [ цифри].
long atol (const char *s); перетворить рядок s у число типу long int (аналогічна функції atoi.)
double atof (const char *s); перетворить рядок символів у дійсне число double. Якщо при перетворенні зустрічається символ, що не може бути перетворена функція повертає 0.
Оброблюваний рядок повинний мати структуру:
[проміжки] [знак числа] [цифра. цифра] [літера е,Е,d або D] [знак порядку] [цифри порядку], наприклад ”-12345.123 ” або ”-12. 345123 Е3 ”
char *ecvt (double vl, int n, int *dec, int *sign ); перетворить число vl у рядок символів, кількість яких дорівнює n символів цифр. Положення десяткової крапки від першої цифри числа повертається в змінній, на яку вказує dec. Знак числа повертається в змінну на який указує sign. Якщо sign = 0 число додатнє, інакше відємне. Отриманий рядок зберігається у внутрішній пам'яті функції, покажчик повертається на початок сформованого рядка.
сhar *fcvt (double vl, int n, int *dec, int *sign ); аналогічна попередній функції, але для ecvt - параметр dec задають загальна кількість цифр, то для fcvt - кількість цифр після десяткової крапки.
сhar *gcvt (double vl, int n, сhar *buf); перетворить число vl у рядок, що поміщає в буфер, покажчик на початок якого є buf, n число цифр у символічному записі перетвореного числа. Отриманий рядок містить символ знака числа і десяткової крапки, якщо число містить менше десяткових цифр, ніж n. У цьому випадку молодша цифра дробової частини відкидається. Якщо перетворене число не міститься в задану кількість цифр n, функція генерує символьний запис в експонентній формі, включаючи в рядок символ Е и знак порядку. Функція повертає покажчик на початок сформованого рядка.
strlen (st) - повертає довжину st без нуль - термінатора '\0'.
Функції перевірки символів
Ці функції знаходяться у файлі <ctype.h>:
isgraph (s) повертає значення ”істина” тобто не нуль, якщо s є друкованим символом і “неістина ” (тобто 0) , якщо s є проміжком або яким - небудь не відображуваним символом.
isprint (s) повертає значення ”істина” тобто не нуль , якщо s є друкованим символом, включаючи проміжок і ”неістина” (тобто 0) у всіх інших випадках.
ispunct (s) повертає значення "істина" тобто не нуль , якщо s є знаком пунктуації(будь-який друкований символ крім проміжку і “неістина” (тобто 0) в інших випадках.
isdigit (s) повертає значення "істина" тобто не нуль , якщо s є цифрою від 0 до 9 і “неістина” (тобто 0) в інших випадках.
isalnum (s) повертає значення "істина", тобто не нуль, якщо s є цифрою або літерою (заголовною або строковою ) і “неістина” (тобто 0) у всіх інших випадках (тобто перевіряє алфавітні і цифрові символи).,
tolower (s) перетворить символ s до нижнього регістра;
toupper (s) перетворить символ s до верхнього регістра;
atoi (s) перетворить рядок s до ціле число;
atol (s) перетворить рядок s до довгого цілого;
atof (s) перетворить рядок s до числа з крапкою, що плаває.
Розглянемо ряд прикладів з використанням строкових функцій .
Приклад 3.5 Ввести список прізвищ (рядків) і відсортувати його за алфавитом.
//P3_5.CPP ( сортування списку прізвищ за алфавитом
#include <iostream.h>
#include <string.h>
void main( )
{
char mst[ 5] [15];
char *ps[5], *ptr;
int і, n, k;
cout << "Введіть прізвища \n";
for( i = 0; i < 5; i++)
{
gets (mst [i] );
ps[i] = mst[i];
}
cout << "\n\t Вихідний список\n\n";
for( i = 0; i < 5; i++)
puts ( ps[ i ] );
// Сортування масиву
n = 5;
for (i = 1; i < n; i++) // кількість переглядів
for ( k = 0; k < ( n i ); k++)
if ( strcmp ( ps[k], ps[k+1] ) > 0)
{
ptr = ps[k];
ps[k] = ps[k+1];
ps[k+1] = ptr;
}
cout << "\n\n\t Відсортований список \n\n";
for ( i = 0; i < 5; i++)
puts ( ps[ i ] );
}
Приклад 3.6 Ввести рядок і видалити в ньому зайві проміжки.
//P3_6.CPP ( видалення зайвих проміжків
#include <iostream.h>
#include <string.h>
void main()
{
char st[] = "Прийшла весна в мої краї.";
int i,j;
for (i = 0; i < strlen(st)-1; i++)
{
if ((st[i] == ' ') &&(st[i+1] == ' '))
{
for (j = i+1; j < =strlen(st); j++)
st[j-1]=st[j];
i-- ;
}
cout << st;
return 0;
}
Приклад 3.7 Визначити позицію входження підрядка в рядок.
//P3_7.CPP ( пошук позицій входження підрядка в рядок.
#include <iostream.h>
#include <string.h>
const int m = 50;
void main()
{
char *pt, mainstr[m], substr[m];
int n, k = 0;
cout << "Введіть рядок " << endl;
cin.getline ( mainstr, m);
cout << "Введіть підрядок" << endl;
cin.getline ( substr, m);
cout << "Головний рядок: " << mainstr << endl;
cout << "Підрядок: " << substr << endl;
pt = strstr ( mainstr, substr );
cout << "Номер входу підрядка в рядок" << endl;
while (pt)
{
k++;
n = pt - mainstr;
cout << k << " n = " << n << endl;
pt = strstr( ++pt, substr );
/* cout << k << " ." << *pt << endl;*/
}
if ( k == 0) cout <<"Підрядок не міститься в рядку" << endl;
}
Приклад 3.8 Знайти заданий символ у рядку.
//P3_8.CPP ( пошук символів у рядку
#include <iostream.h>
#include <string.h>
main( )
{
const int m = 25;
char sim, *pt, str[m];
int n, k = 0;
cout << "Введіть рядок" << endl;
cin.get ( str, m );
cout << "Введіть символ" << endl;
cin >> sim;
pt = strchr ( str, sim );
cout << "Позиції входу символу в рядок" << endl;
while (pt)
{
k++;
n = pt - str;
cout << k << " n = " << n << endl;
pt = strchr(++pt, sim);
}
cout << "К-кість входжень="<<k<<endl;
if(k==0) cout << "Символ не входить у рядок" << endl;
return 0;
}
Приклад 3.9 Ввести список прізвищ і вивести прізвища які починаються з літер "П" і "Ф" і закінчуються на "ко"
//P3_9.CPP ( вивести зі списку прізвища, що починаються з
// літер "П" і "Ф" і закінчуються на "ко"
#include <iostream.h>
#include <string.h>
void main(void)
{
const int n = 5;
char gr [ 5 ] [15], s2[2] = {"kо"};
int і;
cout << "Введіть прізвища" << endl;
for(i = 0; i < n; i++)
cin >> gr[i];
cout << "Список прізвищ" << endl;
for ( i = 0; i < n; i++)
cout << gr[i] << endl;
strrev ( s2 );
cout << "Прізвища на П и Ф" << endl;
for ( і = 0; і < n; і++)
if ( ( ( gr [і] [0] == 'П') || ( gr [і] [0] == 'Ф') )
&& ( strncmp ( strrev ( gr[i] ), s2 ,2) == 0))
cout << strrev( gr[i] ) << endl ;
}
1. Що являє собою значення символьного типу?
2. Як задається тип символьних даних?
3. Що являє собою масив символьного типу?
4. Як уводяться строкові значення?
5. Як порівняnи дані строкового типу?
6. Яке строкове дане більше “стіл” або “стілець”?
7. Наведіть приклад використання операції конкатенації?
8. Як визначити кількість символів вхідних у строкове дане?
9. Які функції мови С++ використовуються для виділення підрядку з рядка?
В усіх завданнях, де не наводиться конкретний вигляд оброблюваних строкових даних, студент вибирає їх довільно відповідно до умови.
1. Слова в тексті розділені проміжками. Підрахувати кількість слів , які починаються з літер “До” і “до”.
2. З тексту вивести слова, що починаються і закінчуються на однакові літери(літеру).
3. З речення вивести саме довге слово.
4. З списку прізвищ вивести прізвища, що починаються і закінчуються на однакові літери(літеру).
5. Визначити, скільки разів літера “а” повторюється у введеному тексті.
6. Ввести текст зі свідомо великою кількістю проміжків між словами. Програмним шляхом видалити з нього зайві проміжки.
7. Вивести слова тексту: “Мед у лісі ведмідь знайшов мало меду, багато бджіл”, що починаються з літери “м”.
8. В списку з 10 прізвищ визначити саме коротке прізвище.
9. В списку з 10 прізвищ визначити саме найдовше прізвище. .
10. Визначити, на якому місці записане саме довге слово в реченні.
11. Віддрукувати слово, що складається з останніх літер усіх слів тексту.
12. З введеного тексту вивести слова, у яких немає цифр
13. З введеного тексту вивести слова, у яких немає літер “о” і “у”.
14. З введеного тексту вивести саме коротке слово.
15. Ввести список з 10 прізвищ, розташованих у довільному порядку й упорядкувати їх за алфавітом.
16. Віддрукувати слово, що складається з перших літер усіх слів тексту.
17. Виділити частину тексту між словами, що вводяться в рядку запиту.
18. Підрахувати скільки разів у вихідному тексті повторюється поєднання літер ТСМ ( або ІМЗ ).
19. Вибрати у вихідному тексті саме довге слово, що не містить сполучення “про”.
20. Ввести невелику програму на С++. Підрахувати скільки у ній операторів “cоut”.
21. Ввести текст:
“Слава світу на Землі!
Слава хлібу на столі!
От він хлібець запашний.”
Віддрукувати окличні речення.
22. Вибрати з уведеного тексту саме коротке слово, що не містить задану приголосну.
23. Ввести текст:
“Не дозволяй душі лінуватися,
Щоб воду в ступі не товкти,
Душа зобов'язана трудитися ,
І день і ніч, і день і ніч! ”
Вивести слова, що містять літеру “о”.
24. Вибрати з вихідного тексту (див. варіант 23 ) саме довге слово, що містить голосну “і”.
25. У невеликій програмі на С++ підрахувати кількість операторів циклу for.
4 ВИРІШУВННЯ ЗАДАЧ З ВИКОРИСТАННЯМ ДАНИХ ТИПУ СТРУКТУРА
4.1 Ціль роботи
даних типу структура
4.2 Методичні рекомендації з організації самостійної
роботи студентів
При підготовці до даної лабораторної роботи рекомендується повторити дані типу структура і застосування структурних типів для вирішування практичних задач.
Структура це сукупність різнотипних елементів, яким привласнюється одне ім'я ( воно може бути відсутнім), що займає одну область пам'яті. Елементи структури називаються полями.
Як і будь-яка змінна, структурна змінна повинна бути описана. Цей опис складається з двох кроків: опис шаблона (тобто складу ) або типу структури й опису змінних структурного типу.
Синтаксис опису структури має вигляд:
struct < ім'я структури >
{ <тип 1 > ім'я поля 1;
< тип 2 > ім'я поля 2. . . . . . . .;
} [ р1, р2. . . .];
де struct службове слово;
< ім'я структури > ім'я типу структури ;
<тип 1>, <тип 2> імена стандартних або визначених типів;
ім'я поля 1, ім'я поля 2, … імена полів структури;
р1, р2. . . .; імена перемінних типу структура.
Приклад 4.1. Обробити дані про здачу студентами сесії по предметах: математиці, фізиці і програмуванні, підрахувати середній бал, отриманий студентами по цим курсам.
Визначимо структуру:
struct stud
{
char fam [25]; // прізвище і ініціали
int mat, fiz, prg; // предмети
float sb; // середній бал
} st1,st2;
Змінні st1 і st2 можна оголосити окремим оператором, наприклад:
stud st1 st2;
Ініціалізація полів структури може ,enb ghjdtltyf або при її описі, або в тілі програми. При описі структури ініціалізація полів може виглядати так:
struct stud
{ char fam [25];
int mat,fiz, prg;
float sb;
}
st1 = { " Кравченко И.С.", 4, 5, 5},
st2 = { "Тесленко А.М.", 3, 4, 5};
Якщо ініціалізація полів буде проведена в тілі програми, то для звертання до імен полів треба спочатку записати ім'я структурної змінної, а потім ім'я поля, що відокремлюється крапкою ( складені поля). Отже, у випадку , коли змінна st1 з'являється в програмі, для її ініціалізації можна записати
stud st1 = {"Кравченко И.С.",4 ,5 ,5); або ініціалізація здійснюється за допомогою складених полів, як представлено в наступній програмі:
// Р 4_1. СPP визначення середнього бала
// використання складених полів
#include < iostream.h >
#include < string.h >
#include < stdio.h >
main ( )
{
struct stud
{ char fam [20];
int mat, fiz, prg;
float sb;
} st1, st2;
strcpy (st1. fam, "Кравченко И.С.");
st1 . mat = 4;
st1. fiz = 5;
st1. prg = 5;
st1. sb = (st1. fiz + st1. mat + st1. prg) / 3;
st2 = st1;
puts (st2. fam); // Виведення прізвища st2;
cout << st2. mat << st2. fiz << st2. prg << st2. sb << endl;
return 0;
}
У цій програмі всім полям структури st1 привласнені відповідні значення. Треба звернути увагу, що поле st1.fam одержує значення шляхом використання функції strcpy (st1.fam, "Кравченко И.С.");. Структурна змінна st2 має ту ж структуру, що і st1, тому справедливо операцію st2 = st1; . Якщо в одній функції використовується тільки один структурний тип, то цей тип можна повідомляти без імені. Наприклад, раніше розглянуту структуру можна оголосити в такий засіб:
struct
{ char fam [25];
int mat, fiz, prg;
float sb;
} st1, st2;
Якщо при описі структур у деякій функції або в межах " видимості" змінних у різних функціях мається багато (але не усі) однакових полів, то ці однакові поля можна об'єднати в окрему структуру і використовувати її при описі інших структур, тобто поля структури можуть самі мати тип "структура". Це називається вкладеністю структур. Наприклад, якщо треба обробляти списки студентів і викладачів університету, причому в студентських списках містяться дані: прізвище і иниціали, дата ( день, місяць, рік) народження, група і середній бал успішності, а в списках викладачів обробляються такі дані: прізвище і ініціали, дата народження, кафедра, посада.
Для обробки списку студентів і викладачів можна оголосити наступні структури:
struct stud
{ char fio [25];
int den,god;
char mes [10];
char grup;
float sb;
}
і
struct prep
{ char fio [25];
int den, god;
char mes [10];
char kaf, dolg;
}
В оголошених типах однакові поля має сенс включити в окрему структуру і використовувати її при описі інших типів. Поетапно це виглядає так:
загальна структура:
struct spd
{ char fio [25];
int den,god;
char mes[10];
}
структура для опису інформації про студентів:
struct stud
{ spd dr;
char grup;
float sb
} st1,st2;
структура для опису інформації про викладачів:
struct prep
{ spd dr;
char kaf [10] ;
char dolg [15];
} pr1,pr2;
У структурах stud і prep для оголошення поля, що містить дані про прізвище і дату народження використовується раніше описаний тип spd. Тепер до поля fio, den, god, mes можна звернутися, використовуючи запис наступного вигляду:
st1 . dr . fio
Наприклад, при записі функції введення gets (st1 . dr . fio); або pr1 . dr . fio .
Після оголошення структурного типу перемінних, для роботи з їх полями можна використовувати і покажчики, тоді опис структури буде мати вигляд:
struct stud
{ char fam [25];
int mat, fiz, prg;
float sb;
} st1, *pst;
Тепер доступ до полів може здійснюватися двома способами :
використовуючи оператор (*) , наприклад,
gets ((*pst) . fam); (*pst) . fiz = 5;
використовуючи спеціальний покажчик на структуру "->", наприклад,
gets ( pst -> fam); pst -> fiz = 5; і т.д.
Крім того до змінної st1 можна звертатися, указуючи поля через символ крапка, як це робилося раніше.
Дані структурного типу можна об'єднати в масиви, наприклад, використовуючи раніше розглянуту структуру можна записати:
struct stud
{ char fam [25];
int mat, fiz, prg;
float sb;
} spis[15], *sp = &spis[0];
або, якщо масив описується не при описі структури, то його можна оголосити у вигляді:
stud spis [15]; .
Доступ до елементів масиву може виконаються з використанням індексу або через покажчик константу, яким є ім'я масиву:
strcpy( spis [1] . fam, " ");
spis [1] . fiz = 5;
або
strcpy ((sp +1) -> fam, " ");
(sp + 1) -> fiz = 5;
Це можна записати також у вигляді:
strcpy ((* (spis +1 )) . fam, " ");
(*(spis+1)) . fiz = 5;
Тут потрібно зовнішня пара дужок, тому що операція (.) " крапка" має пріоритет вище, ніж операція за адресою (*).
Розглянемо використання даних структурного типу на наступному прикладі.
Приклад 4.2. Ввести в комп'ютер відомість успішності студентів групи з 25 чоловік, які сдають сесію по предметах: фізиці, математиці, і програмуванню і підрахувати:
середній бал, отриманий кожним студентом;
середній бал групи за кожним предметом;
вивести на екран відмінників по програмуванню.
Програма буде мати вигляд:
// P4_2. CPP обробка відомості успішності
// Використання даних типу структура
#include < iostream.h >
#include < string.h >
#include < stdio.h >
#include < iomanip.h >
void main(void)
{
const k = 5;
int n = 1, i;
float sm, sf, sp;
struct stud
{ char fam[25];
int mat, fiz, prg;
float sb;
} ved[k];
sm = sf = sp = 0;
cout << "Введіть прізвище й оцінки mat, fiz, prg \n " ;
for ( i = 0; i < k; i++)
{
gets ( ved[i]. fam );
cin >> ved[i]. mat >> ved[i]. fiz >> ved[i]. prg ;
ved[i]. sb = ( ved[i]. mat + ved[i]. fiz + ved[i]. prg) / 3;
sm += ved[i]. mat;
sf += ved[i]. fiz;
sp += ved[і]. prg;
}
cout << "\t Відомість успішності групи \n\n";
cout << "\t";
for ( i = 0; i < 47; i++) cout << "-"; // Верхня риса
cout << "\n";
cout << "\t \t прізвище\t мат фіз прогр порівн.бал \n";
for ( i = 0; i < 47; i++) cout << "-"; // Верхня риса
for ( i = 0; i < k; i++)
{
cout << "\t" << i + 1 << " " << setw(17)
<< setiosflags ( ios :: left ) << ved[i]. fam;
cout << ved[i]. mat << " " << ved[i]. fiz <<
" " << ved[i]. prg << " " << ved[i]. sb << "\n";
}
cout << "\t";
for ( i = 0; i < 47; i++) cout << "-"; // Нижня риса
cout << "\n\t" << setw(16) << setiosflags ( ios :: right )
<< "Порівн. бал";
cout << " " << sm / k << " " << sf / k << " " << sp / k << "\n\n";
cout << "\t Відмінники по програмуванню: \n\n";
for ( i = 0; i < k; i++)
if ( ved[i]. prg == 5)
{
cout << "\t" << n << " " << ved[i]. fam << "\n";
n++;
}
}
Результат роботи програми буде мати вигляд:
Відомість успішності студентів
_______________________________________________
прізвище мат фіз прогр порівн.бал
_______________________________________________
Авдєєв И.М. 3 4 4 3.7
Биків Т.Б. 5 5 4 4.6
Волков А.П. 4 5 5 4.6
_______________________________________________
Порівн. бал 3.8 4.6 4.8
Відмінники по програмуванню:
Волков А.П.
Поля структури можуть також бути масивами, наприклад, у раніше розглянутій структурі stud можна оцінки по різних предметах об'єднати в масив. Тоді таку структуру можна описати у вигляді:
struct stud1
{ char fam [25];
int pr [3];
float sb
} st1 [10], *pst = &st1 [0]; ,
тепер до полів можна звертатися одним з наступних способів:
((*pst). fam) // gets (( *pst) .fam);
( pst -> pr [0] ) // cin >> pst -> pr[0] >> pst -> pr[1];
// або cin >> pst -> * (pr +1).
У бібліотеці <stdlib.h> для пошуку і сортування структурних змінних маються спеціальні функції. Так , функція швидкого сортування структурних елементів масиву по заданому полю має вигляд :
#include < stdlib.h >
void qsort (void *base , n , width,
int (* fcmp ) (const void *elem 1, const void -> elem2)) ,
де base покажчик на перший елемент масиву;
n кількість елементів масиву;
width -довжина елементів масиву в бітах.
При виконанні сортування функція qsort ( ) звертається до заданого користувачем функції.
Функція задається покажчиком на функцію:
int (*fcmp) ( const void *elem1, const void *elem2) .
Функція, на яку вказує fcmp , виконує порівняння двох елементів масиву, на які вказує elem1 і elem2.
Функція повинна повертати значення:
< 0, якщо *elem1 < *elem2;
= 0, якщо *elem1 = *elem2;
> 0, якщо *elem1 > *elem2;
Якщо *elem1 > *elem2 , то елемент, на який указує elem1 розташовується в масиві раніш; "колишній" елемент розташовується в упорядкованому масиві пізніше.
Користувач задає порівнювані поля структурних змінних. Він також може змінити порядок, у якому будуть упорядковуватися елементи, що досягається зміною знака значень, що повертаються з функції, на протилежні; може змінити поля, по яких виконується сортування.
У бібліотеці <stdlib.h> існує також функція пошуку змінних структурного типу в масиві цих змінних.
4.3 Контрольні питання
1. Що таке дані типу структура і які типи даних вони містять?
2. Як описуються дані типу структура?
3. Які існують засоби ініціалізації полів структури?
4. Що таке “вкладеність“ структур?
4.4. Індивідуальні завдання
1. З відомості працівників цеху визначити, скільки в цеху чоловіків-токарів?
2. Скільки в групі студентів-відмінників (всі оцінки 5) і студентів невстигаючих?
3. Є чи в групі студенти, що грають у волейбол , зріст яких більше 180 см?
4. Список студентів відсортувати за зменщенням середнього бала.
5. Ввести в довільному порядку відомості про студентів групи. Вивести прізвища студентів по групах: встигають ”добре”,” задовільно”,” незадовільно”.
6. Віддрукувати список робітників-жінок ціху пенсійного віку.
7. Ввести в пам'ять розклад електропоїздів прямуючих з Харкова через Мерефу. Які з потягів прямують тільки до Мерефи?
8. Хто зі студентів групи має самий великий зріст і вагу ?
9. Ввести відомості про дату народження студентів групи, вивести дані в такому порядку: спочатку - про народжених в 1-ої декаді, потім у 2-ий і 3-їй декадах.
10. Зі списку студентів групи вивести на екран два списки: перший містить прізвища дівчин, другий прізвища юнаків.
11. Список студентів групи ввести в довільному порядку, а вивести на екран по групах, кожна група належить до якого-небудь знака зодіаку.
12. За яким предметом в студента з заданим номером по журналу краща оцінка за підсумками сесії?
13. Ввести в пам'ять результати змагань по лижних гонках. Показати п'ять кращих результатів окремо для юнаків і дівчин.
14. За результатами лижних змагань у трьох групах сформувати збірну команду з 7 чоловік.
15. Ввести списки двох студентських груп, упорядкованих за зменшенням середнього бала. Виконати злиття списків в один список, упорядкований за тою же відзнакою.
16. В одному списку інформація про студентів, що приймали участь в олімпіаді по математиці, в іншому по інформатиці. Сформувати третій список з учнями, що брали участь в обох олімпіадах.
17. З якого предмета в заданого студента краща оцінка за підсумками навчального року ?
18. Хто зі студентів-спортсменів здав усі випускні іспити на "добре" і "відмінно" ?
19. Хто краще учиться в групі - дівчата або юнаки?
20. Є чи в групі студенти, що мають оцінку 4 або 5 по інформатиці і грають в шахи ?
21. Знаючи прізвища улюблених письменників ваших друзів, надрукувати прізвища п'яти найбільш популярних письменників.
22. Обчислити середній бал групи і роздрукувати список студентів, що мають середній бал вище за середнє бала групи.
23. Роздрукувати список студентів, прізвища яких починаються з букви "А", і їхньої оцінки за час навчання.
24. За підсумками останньої сесії роздрукувати список відмінників і тих, що вчаться добре упорядкований за алфавітом.
25. Обчислити середній бал групи і роздрукувати список студентів за зменшенням середнього бала.
5 ВИКОРИСТАННЯ ФУНКЦІЙ ПРИ РОЗРОБЦІ ПРОГРАМ
5.1 Ціль роботи
Придбання навичок складання і використання функцій при розробці програм.
5.2 Методичні вказівки з організації самостійної роботи
студентів
При підготовці до роботи варто вивчити матеріал з організації і використанню функцій. Звернути увагу на те, що програма мовою С++ складається з розділу визначень (описів) і набору однієї чи декількох функцій.
Функція це логічно завершена сукупність описів і операторів, призначених для виконання визначеної задачі.
У мові С++ немає розподілу на основну програму і підпрограми, на процедури і функції і т.д. Однак серед функцій повинна бути одна з ім'ям main, що може знаходитися в будь-якому місці програми. Ця функція виконується завжди першою і закінчується останньою. Будь-яка функція має однакову структуру, що має вигляд :
[тип результату ] ім'я функції ([список формальних аргументів])
{
// тіло функції
опис даних ;
оператори ;
[return] [вираз];
}
тут квадратні дужки [ ], як звичайно вказують, що розташованана в них конструкція може бути відсутньою ;
тип результату будь-який базовий або раніше описаний тип значення, яке повертається функцією (необов'язковий параметр), якщо він відсутній, тоді тип результату буде цілий (int); цей параметр може бути описаний ключовим словом (void), у цьому випадку функція не повертає ніякого значення (результату). Якщо параметр заданий із зірочкою (*) функція повертає покажчик на об'єкт, або на одержання адреси об'єкта (& ) (в операторі return);
ім'я функції будь-яке ім'я, що складається з літер, цифр і знака "_" (підкреслення), що починається літерою або знаком "_", або ім'я main, за ім'ям функції завжди повинна стояти пара круглих дужок ( ), у яких записуються формальні параметри, а якщо їх немає, тоді порожні дужки. Варто мати на увазі, що фактично ім'я функції це особливий вигляд покажчика на функцію, його значенням є адреса початку входу у функцію;
список формальних аргументів визначає кількість, тип і порядок проходження переданих у функцію вхідних аргументів, що друг від друга розділяються комою. У випадку, коли список відсутній, це поле буде порожнім ( ), або містити ключове слово ( void ) . Формальні параметри функції цілком локалізовані в ній і недоступні для будь-яких інших функцій.
Список формальних аргументів повинний мати наступний вигляд:
( [const] тип 1 [параметр 1] , [const] тип 2 [параметр 2],. . . )
У цьому списку не можна групувати параметри одного типу, указавши їх тип один раз, для кожного параметра треба вказувати його тип. Слово const повідомляє компілятору, що значення параметра не повинне змінюватися функцією ( це необов'язковий атрибут). За замовчуванням усі формальні параметри передаються за значенням, тобто якщо вони змінюються в тілі функції, то за її межами залишаються без зміни, оскільки передаються не самі значення, а їхні копії. Ці копії створюються усередині функції, це ілюструє, наприклад, такий фрагмент програми:
void fun ( int p)
{
++ p;
cout << " p=" << p << endl;
}
void main ( )
{
int x = 10;
fun (x); // виклик функції
cout << "x=" << x << endl;
}
У результаті роботи цього фрагмента програми буде виведено: р=11, х = 10, оскільки для виклику функції fun(x) до неї передається копія значення рівного 10, пшд час виконання цієї функції значення p збільшується на 1, тобто (++р) і, тому виводиться р = 11, але за межами функції зазначене значення не змінюється. Якщо треба змінити змінну оригінал, тобто передати зміну параметра за межами тіла функції, то можна передати значення параметра за посиланням або використовувати параметр-покажчик. Тоді, використовуючи параметр- посилання, одержимо :
// Використання параметра - посилання
void fun (int &р)
{ ++p;
cout << "p = " << р << endl;
}
void main ( )
{
int x = 10;
fun( x );
cout << "x=" << x << endl;
}
У результаті буде виведена інформація: р=11 і х=11.
Під час використання аргументу-покажчика програма буде мати вигляд:
// Використання параметра - покажчика
void fun2 (int *p)
{
++*р;
cout << "*p = " << *p << endl;
}
void main ( )
{
int x = 10;
fun2 ( &x );
cout << "x = " << x << endl;
}
У цьому випадку одержуємо той же результат, тобто р = 11 і х = 11.
Під час використання таких параметрів у функцію і з неї передається не значення, а адреса, тому зміна значення цієї змінної усередині функції передається за її межі (в інші функції). Якщо треба, щоб які-небудь параметри не змінювали свої значення усередині функції, то їх варто оголосити як параметри-константи, використовуючи модифікатор const .
Тіло функції може складатися з описів змінних і операторів. Змінні, котрі використовуються при виконанні функції, можуть бути глобальні і локальні. Якщо змінні описані (визначені) за межами функції, вони будуть глобальними. З їхньою допомогою можна передавати дані у функцію, не включаючи до складу формальних аргументів. У тілі функції їх можна змінювати і потім отримані значення передавати в інші функції.
Змінні, описані в тілі функції, називаються локальними або автоматичними. Вони існують тільки під час виклику функції. Як тільки відбувається повернення з функції, система видаляє локальні змінні і звільняє пам'ять. Отже, між викликами функції значення локальних змінних губиться, тому ініціалізацію локальних перемінних треба робити щораз при виклику функції.
У випадку, коли необхідно зберегти значення локальних змінних між викликами функції, їх треба описати як статичні за допомогою службового слова static, наприклад:
static int x, y; або static float p = 3.25;
Статична змінна схожа на глобальну, але доступна тільки в тій функції, у якій вона оголошена.
Таким чином, можна зробити висновок:
параметри функції передаються в неї за значенням, тому за межами функції вони не змінюються, тобто їх не можна використовувати для передачі результату роботи функції;
при передачі результату функції за її межі використовуються: або передача параметрів за посиланням (&р); або передача за покажчиком (*р), у цьому випадку під час звертання до функції застосовується символ адреси & , тобто (&р); або як параметр функції варто використовувати глобальні змінні;
локальні (звичайні) змінні використовуються в тілі функції, існують тільки під час роботи функції, а при виході з неї знищуються, тому такі змінні називаються автоматичними і їх можна використовувати тільки для перетворень усередині функції;
якщо виникає необхідність збереження значень локальних змінних між викликами функції, то вони повинні бути оголошені як статичні, тобто з описом static, наприклад:
static char st[ ] = "Тесленко А.М.";
у якості вхідних (і вихідних) формальних аргументів функцій можуть використовуватися масиви як фіксованої довжини, так і змінної; якщо використовується в якості формальний масив змінної довжини, то обов'язково серед аргументів функції повинна бути змінна, що вказує длину масиву, наприклад:
int minmas (int mas [ 50]); // Масив фіксованої довжини
int minmas (int mas [ ], int n); //Масив змінної довжини
int minmas (int *mas, int n); //Масив змінної довжини
усі масиви формальні аргументи передаються за адресою, тобто як покажчики;
на початку програми записується заголовок використовуваної функції, який називається прототипом , наприклад:
double sgr (double); // Прототип функції sqr
. . . . . . . . .
int main ( )
{
cout << "5**2 = " << sgr (5) << endl; // Виклик функції
}
При записі прототипу можна перелічувати тільки типи формальних елементів без імен, і наприкінці необхідно ставити символ ";" , а в описі функції цей символ після заголовка не записується.
в останніх версіях мови С++ з'явилася можливість передавати дані за замовчуванням. У цьому випадку при написанні функції аргументам присвоюються початкові значення, що можуть мати всі аргументи або частину з них. У результаті задовольняються наступні вимоги: якщо якому-небудь аргументу надане значення за замовчуванням, то всі аргументи, що стоять за цим параметром (тобто записаним праворуч), повинні мати значення за замовчуванням. Таким чином, список параметрів поділяється на дві частини: параметри, що не мають значення за замовчуванням, і параметри, що мають такі значення.
Під час виклику функції для параметрів, що не мають значень за замовчуванням, обов'язково повинний бути фактичний аргумент, а для параметрів, що мають значення за замовчуванням, фактичні аргументи можна опускати, якщо ці значення не треба змінювати. Якщо для деякого параметра, що має значення за замовчуванням, опущений фактичний аргумент, то і для всіх наступних (тобто записаних пізніше) параметрів фактичні аргументи повинні бути опущені, тобто їх значення передаються у функцію за замовчуванням, наприклад, опишемо три функції :
void funct1 ( float x, int y, int z =80 )
{
cout << "x = " << x << " y= " << y << "z=" << z << endl;
}
void funct2 ( float x, int y = 25 , int z = 100 )
{
cout << "x=" << x << "y=" << y << "z=" << z << endl;
}
void funct3 ( float x=3.5 , int y= 40, int z =200 )
{
cout << "x = " << x << "y = " << y << "z = " << z << endl;
}
main ( )
{
funct1 ( 5.1 , 10 ); // за замовчуванням один аргумент z
funct2 ( 10.2 ); // за замовчуванням два аргументи y ,z
funct3 ( ); // за замовчуванням всі аргументи
}
На екрані буде виведено: x =5.1 y = 10 z = 80
x =10.2 y = 25 z = 100
x =3.5 y = 40 z = 200
З цих ілюстраційних програм видно, що аргумент за замовчуванням це той, значення якого задане при описі заголовка функції, а при її виклику цей аргумент можна не вказувати. Якщо замість параметра, заданого за замовчуванням при звертанні до функції, записується інше значення фактичного параметра, то значення за замовчуванням заміюються заданим фактичним значенням. Так, наприклад, в останньому програмному фрагменті при виклику функції funct (13.5, 75); на екрані буде виведено :
x = 13.5 y =75 z = 80 , тобто z - прийнято за замовчуванням.
5.2.1 Використання покажчиків на функцію
Синтаксис мови С++ дозволяє використовувати покажчик на функцію. Ім'я будь-якої константи це покажчик константа, дорівнює адресі початку входу у функцію, тобто адресі її першої машинної команди. Крім констант можна також описувати покажчики - змінні на функцію у вигляді:
type (*name) (список аргументів); ,
де type тип значення, що повертається функцією, ;
name ім'я змінної - покажчика на функцію.
Покажчики на функцію використовуються в наступних основних випадках :
при використанні їх як формальні аргументи в інших функціях;
для непрямого виклику інших (резидентних) функцій (програм), початок входу в який записується у відоме місце ОП.
Приклад 5.1 Обчислення суми і різниці двох чисел програмно реалізувати з використанням покажчика на функцію для доступу до інших функцій
//P5_1.CPP використання покажчика на функцію для доступу
// до інших функцій difference( ) і sum( ).
#include < iostream .h >
int difference ( int, int ); // Прототип функції
int sum ( int, int );
void main ( )
{
int (*fun) (int, int );
int x = 20, y = 5, z ;
fun = difference ; // Присвоювання адреси одного покажчика - іншому
z = fun (x, y);
cout << "z = " << z << еndl;
fun = sum; // Присвоювання нової адреси покажчика
z = fun (x , y );
cout << "z = " << z << endl;
}
int difference (int a , int b) // Опис функції
{ return (a - b);
}
int sum ( int a, int b )
{ return (a + b);}
Як і звичайні змінні, покажчики на функції можна об'єднати в масиви, наприклад, якщо описати функції, тобто їхні прототипи у вигляді:
int god ( const void*, const void * ) ;
int chena ( const void*, const void *) ;
int nazv ( const void*, const void * ) ;
int avtor ( const void*, const void * ) ; ,
то можна описати функцію
int (*fcmp[4]) () {god, chena, nazv, avtor} ; .
У результаті вийшов масив функцій, доступ до елементів цього масиву звичайний, наприклад:
int i =0;
fcmp [i] ( pt1,pt2 ); // це виклик функції god ( pt1, pt2);
Варто звернути увагу, що замінивши індекс, можна викликати іншу функцію і т.д.
Крім повернення результату виконання функцій у вигляді даних за значенням, можливе також повернення за допомогою операцій разіменування "*" чи одержання адреси "&".
Операція разіменування "*" означає, що функція повертає адресу на об'єкт. Функції в такому випадку з'являються як покажчики на функцію, тобто в наступному вигляді:
type * fname (список формальних аргументів) .
Описані в такий спосіб функції повинні повертати покажчик на тип (адреса), наприклад:
сhar* dayweek (int data)
{
static char *weekday[ ] = {"Sunday", "Monday", "Tuesday",
"Weduesday", "Thursday", "Friday", "Saturday"}
return weekday [data % 7];
}
Тут функція dayweek одержує значення data, тобто число днів, що пройшли з якоїсь визначеної дати, і повертає день тижня у вигляді покажчика на char* оскільки weekday це масив покажчиків на char , що належить типу char*.
Під час оголошення функції як покажчика на функцію результат можна передавати шляхом одержання адреси, що позначається "&". Така функція буде мати наступну структуру:
type *funame (список формальних аргументів)
{
static type x;
// далі виникає тіло функції
return &x;
}
Оскільки значенням покажчика є адреса, то функція може повернути адресу об'єкта того ж типу, що і тип покажчика, що повертається. Якщо необхідно повернути результат функції за посиланням, то переважніше використовувати операцію одержання адреси "&", і функцію описувати у вигляді :
type& funame (список формальних аргументів) .
5.2.2 Використання масивів - параметрів функцій
Як аргументи (параметрів) функцій можуть бути не тільки змінні, але і масиви. У цьому випадку можна використовувати як масиви фіксованого розміру, так і невизначеного (масиви змінної довжини). При використанні масивів фіксованої довжини в заголовку функції в списку формальних аргументів указується тип масиву і його розмір, наприклад:
vоid sort (int mas [ 30 ]); .
Якщо описується функція з масивом змінної довжини, то в заголовку вказується тип масиву невизначеного розміру, і обов'язково ще один параметр, за допомогою якого задається розмірність масиву, наприклад:
void sort ( int mas [ ], int n ) ; .
Усі масиви у функції передаються за адресою (як покажчики), тому у випадку зміни масивів у функції , ці зміни зберігаються при поверненні в зухвалу функцію.
Приклад 5.2 Навести приклад програмної реалізації , у якій відбувається передача символьного масиву у функцію .
//P5_2.CPP використання масивів параметрів функцій
#include < iostream.h >
#include < string.h >
void fun1 (char st [15]);
int main ( )
{
char p[15] ="стіл ";
fun1 (p);
cout << "p=" << p << endl; // p="стілець "
return 0;
}
void fun1 ( char st[15] )
{
cout <<"p=" << st << endl; // стіл
strcpy (st, "стілець ");
}
Результати виконання програми :
р=стіл
р=стілець
Як параметри функцій можна використовувати не тільки одновимірні, але і багатовимірні масиви. При цьому використовуються масиви як фіксованої розмірності, так і невизначеної довжини.
При використанні багатовимірного масиву фіксованого розміру в заголовку функції вказуються значення розмірностей масиву, наприклад:
void fun1 (int mat [7][10]); // використовується матриця mat(7,10)
Якщо використовується багатовимірний масив невизначеної довжини, то невизначеним може бути тільки один вимір розмірності, що повинен бути першим, наприклад:
void fun2 ( int mat [ ] [10], int rows, int cols );
Приклад 5.3 Для заданої матриці зробити обчислення середнього значення кожного її стовпця з використанням функції введення розмірності матриці, функції введення матриці і функції одержання середнього значення стовпців.
// P5_3.CPP обчислення середнього значення
// кожного стовпця матриці
#include <iostream .h>
const int mincol = 1;
const int maxcol = 20;
const int minrow = 2;
const int maxrow = 30;
//Функція getnum ( ) для введення кількості рядків і стовпців
int getnum (const char *elemtype , int low , int high )
{
int n;
do
{
cout << " Введіть кількість " << elemtype
<< " N від [" << low << "] до [" << high << " ] : ";
cin >> n;
}
while (( n<low) || (n>high));
return n;
}
// Функція inmatr ( ) введення елементів матриці
void inmatr ( float matr [ ] [maxcol], int rows , int cols);
{
for (int i =0; i<rows; i++)
{
cout << "Введіть"<< i << "рядок матриці " << endl;
for ( int j =0; j < cols ; j++)
cin >> matr [i][j];
}
cout << endl;
}
// Функція srcols ( ) одержання середніх значень стовпців
void srcols ( float matr [ ] [maxcol] , int rows , int cols )
{
float sum , sr;
for ( int j = 0; j < cols; j++ )
{
sum =0.0;
for ( int i = 0; i < rows; i++)
sum += matr [i][j];
sr = sum / rows;
cout << "середнє значення стовпця" << j << " = " << sr << endl;
}
}
// Головна програма
int main ( )
{
float matr [maxrow] [maxcol];
int rows, cols;
// Уведення кількості рядків і стовпців
rows = getnum ( "rows", minrow, maxrow );
cols = getnum ( "colnums" , mincol , maxcol);
// Уведення матриці
inmatr ( matr, rows , cols);
// Обчислення середнього значення стовпців матриці
srcols (matr , rows , cols);
return 0;
}
5.2.3 Використання функції як параметра значень
Іноді приходиться як формальні аргументи (параметрів) функції використовувати інші функції. Така ситуація виникає, якщо в деякій функції при звертанні до неї, треба викликати іншу функцію.
Параметр - функція записується у вигляді прототипу, тобто вказується тип функції, її ім'я й у дужках перелік типів формальних аргументів, або типів і імен формальних аргументів.
Приклад 5.4 Скласти програму c використанням функції обчислення інтегралів методом трапецій (точність обчислення е =10-3 ).
// P5_4.CPP обчислення інтеграла методом трапеції
// використання функції як параметра значення
#include <iostream .h>
#include <math.h>
const float e =1 e-3;
float fn1 (float x ) // підінтегральна функція 1-го інтеграла
{
return sgrt (1 +log (x));
}
float fn2 ( float x ) // підінтегральна функція 2-го інтеграла
{
return log (1 +pow (x,2)) / (1+pow (x,2));
}
float ft (int n, float a ,float b , float fun( float )) // функція методу трапецій
{
int i;
float s1 ,h, s=0;
do
{ s1 =s;
h = (b -a ) /n;
s = ( fun (a) +fun (b) ) / 2;
for ( i = 1; i <= n-1; i++)
s += fun ( a + i *h );
s *= h; n *= 2;
} while ( fabs ( s-s1 ) > e );
return s; }
int main ( )
{
float y;
y = ft ( 20 , 2 , 2, 3.0, fn1 ) +ft ( 20, 0, 1.0, fn2 );
cout << "y=" << y << endl;
return 0;
}
Результат виконання програми :
y = 1.29012
5.2.4 Звертання до функції і передача результату
Для звертання до функції досить написати її ім'я й у дужках записати значення або перелік фактичних аргументів. Фактичні аргументи повинні бути записані в тій же послідовності, що і формальні і мати відповідний тип (крім аргументів за замовчуванням і перевантаженими функціями). Якщо формальними аргументами функції є параметри значення й у ній не використовуються глобальні змінні, то функція може передати в програмуб яка Ії викликає, лише одне значення, що записується в операторі return . Це значення передається в місце виклику функції. Фрагмент програми, що підтверджує вищевикладене може мати вигляд :
double sgr (double);
main( )
{
cout << "Квадрат числа=" << sgr ( 10 ) << endl;
}
double sqr (double p)
// Повернення за значенням
{
return p*p;
}
У результаті буде виведено:
Квадрат числа = 100.
Використовуючи оператор return можна також організувати достроковий вихід з функції. Якщо з функції треба передати не одне, а кілька значень, то можна або використовувати передачу параметрів за покажчиком, або використати посилання, глобальні змінні, або масиви.
Ім'я функції це константа - покажчик на функцію, що вказує на адресу місця входу (адреса першої машинної команди) функції. Слід зазначити, що можливо також опис і покажчиків перемінних на функції. Для цього використовується операція разіменувания "*", функції описані в такий спосіб повинні повертати покажчик на тип, тобто його адреса.
Приклад 5.5 Обчислити функцію загального вигляду для заданого значення аргументу x з використанням функції, у яку коефіцієнти a, b і c можуть бути введені за замовчуванням.
// P5_5.CPP обчислення квадратної функції
// коефіцієнти квадратної залежності можуть
// вводитися у функцію "за замовчуванням"
#include < іоstrеаm.h >
float ur ( float x, float а=0., floatb b =0.,float c=0.);
int main ( )
{
float а =1., b = 2., c = 3., x = 0.5, y;
cout << " Уведені всі аргументи " << endl;
y = ur ( x, a, b, c);
cout << " y = "<< y << endl;
cout << " Введені аргументи x, a, b " << endl;
y =ur ( x, a, b);
cout << " y = "<< y << endl;
cout << " Введений аргумент x " << endl;
y =ur ( x );
cout << " y = "<< y << endl;
}
// Функція обчислення квадратної функції
float ur ( float x, float a, float b, float c );
{
return a * x * x + b * x + c;
}
Результати виконання програми:
Уведено всі аргументи
y = 4.25
Уведені x, a і b
y = 1.25
Введено аргумент x
y = 0
5.2.5 Перевантаження функцій
У мові С++ можна використовувати перевантаження функцій, тобто можливість визначати функції з одним ім'ям, але з різним типом і кількістю формальних параметрів.
Основне достоїнство перевантажених функцій це можливість визначати кілька функцій з тим самим ім'ям, але з різними типами і числом параметрів.
Приклад 5.6. Зробити програмну реалізацію з використанням перевантаження функцій.
#include <iostream .h>
#include <string.h>
int funp (int x) // 1.
{ return x*x; }
int funp (unsigned x) // 2.
{ return -x*x; }
char funp (char x) // 3.
{ return x+3; }
int funp (int x, char *y) // 4.
{ return x*strlen ( y); }
int funp (int x , char y) // 5.
{ return x*y; }
float funp (float r) // 6.0
{ return r*r; }
float funp (double r) // 7.
{ return r+r; }
int main ( )
{
cout << funp(5) << endl ; // Буде 25
cout << funp ((unsigned)10) << endl ; // Буде 100
cout << funp ( 'а') << endl ; // Буде d
cout << funp (4,"abc") << endl ; // Буде 12
cout << funp ( 4 , 'а') << endl ; // Буде 388
cout << funp( 1.2)<< endl ; // Буде 1.44
cout << funp( (double) 4.5) << endl ; // Буде 9
return 0;
}
У заголовку функції завжди вказується тип її імені, а в самій підпрограмі цьому імені повинне бути привласнене значення, що повертається в головну програму замість звертання до функції.
5.3 Контрольні питання
1. Що таке функція і яка її структура?
2. Що означає передача параметрів у функцію за значенням, за посиланням і за покажчиком?
3. Що таке локальні і глобальні змінні?
4. Як використовувати покажчики на функцію?
5. Які способи передачі і повернення результату обчислень функції?
6. Як використовувати одновимірні масиви як параметри функції?
7. Які особливості використання багатовимірних масивів як аргументи функції?
8. Чи можна обробляти у функції масиви змінної довжини?
9. Чи може функція передавати кілька результатів у місце виклику?
10. Що таке перевантаження функцій?
5.4 Варіанти індивідуальних завдань
1. Розробити функцію , що збільшує всі негативні елементи масивів A(12), B(10), C(8) на 10.
2. Розробити функцію видалення підрядка в n символів з к- ой позиції .
3. Скласти функцію обчислення найбільшого загального дільника 2-х чисел.
4. Обчислити площу багатокутника за допомогою складеної функції , що визначає площу по координатах його вершин.
5. За допомогою функції визначення середнього значення елементів масиву обробити два масиви різної довжини.
6. Скласти функцію визначення середнього арифметичного і середнього геометричного значень елементів масиву.
7. Розробити функцію пошуку максимального елемента масиву і застосувати її для двох масивів різної довжини.
8. Розробити функцію сортування одновимірних масивів за зростанням і застосувати її для сортування чотирьох масивів довільної довжини.
9. Негативні елементи матриць A(5,4), B(3,2), C(4,4) записати в одновимірний масив.
10. Розробити функцію, що обчислює суму діагональних елементів квадратної матриці , і з її допомогою знайти суми діагональних елементів трьох матриць .
11. Скласти функцію визначення суми і кількості елементів, розташованих між мінімальним і максимальним елементами масиву. Використовуючи цю функцію, обробити три одновимірних масиви різноі довжини.
12. За допомогою розробленої функції підрахунку кількості і суми парних елементів одновимірного масиву обробити три одновимірних масиви різної довжини.
13. Три групи студентів здали іспит. Розробити функцію і з її допомогою вивести список студентів кожної групи за зменшенням оцінок .
14. Розробити функцію знаходження найдовшого слова в рядку. Ввести текст і одержати фразу із самих довгих слів.
15. Розробити функції обчислення площ трикутника за формулою Герона і за формулою з використанням основи і висоти. Роботу функцій перевірити при визначенні площ трьох довільних трикутників.
16. Скласти функцію підрахунку кількості слів у реченні.
17. Розробити функцію виділення в тексті слів-паліндромів ( тобто слів, що читаються однаково ліворуч - праворуч і праворуч - ліворуч) і з її допомогою обробити введений текст.
18. Скласти функцію визначення в кожнім стовпці матриці кількості негативних елементів і використовувати її для обробки трьох матриць .
19. Розробити функцію визначення коренів квадратного рівняння і функцію перевірки цих коренів за теоремою Вієта. Використовуючи ці функції, знайти корені двох квадратних рівнянь .
20. Визначити скільки разів кожна літера з алфавіту зустрічається в тексті з застосуванням функції , що виконує таку операцію для заданої літери.
21. Розробити функцію визначення суми членів арифметичної прогресії і реалізувати її для двох арифметичних прогресій з різною кількістю членів .
22. Розробити функцію знаходження максимального елемента масиву і його номера і реалізувати її для обробки трьох масивів довільної довжини.
23. Скласти функцію перестановки максимального і мінімального елементів масиву і застосувати її для обробки двох двовимірних масивів.
24. Розробити функцію сортування масиву за зменшенням і з її допомогою обробити три одновимірних масиви довільної довжини .
25. Скласти функцію обчислення середнього значення елементів масиву й знаходження кількості чисел, що перевищують цю величину. Застосувати розроблену функцію для обробки двох одновимірних масивів.
6.1 Ціль роботи
Навчитися виконувати типові операції з файлами: створення, перегляд і корегування.
6.2 Методичні вказівки по організації самостійної роботи
У процесі підготовки до лабораторної роботи рекомендується вивчити порядок опису файлу, передачу даних у файл і їх читання.
Як елементи файлу можна використовувати будь-які дані мови С++ (числа, символи, рядки, масиви і структури).
При використанні великої кількості оброблюваних у програмі даних доцільно їх записувати на диск, тобто створити на диску файл даних. Перед створенням, записом даних у файл або читанням їх з файлу, цей файл треба спочатку відкрити.
У процесі введення-виведення з використанням стандартних пристроїв (клавіатури й екрана) у програму варто включити заголовний файл iostream.h, у якому міститься опис відповідного класу iostream, тобто на початку тексту програми поміщають директиву :
#include <iostream.h>
Файлове введення-виведення і необхідні функції-члени введення-виведення описані в заголовному файлі fstream, що містить опис основних класів і методів.
Існують також додаткові файли бібліотеки введення-виведення, що містять більш спеціалізовані функції члени введення-виведення.
Для відкриття файлу на диску використовується функція-член класу fstream, що має наступний прототип (заголовок):
void open (const char *filename, int mode, int m = fіlebuf :: openprompt);
де filename ім'я файлу, що відкривається, у якому при необхідності можна вказати шлях;
mode параметр, що задає режим введення , у файлі fstream визначені значення цього режиму і їх зміст;
m параметр, що задає захист файлу, що за замовчуванням приймає значення, заданий константою filebuf :: openprompt ;
Параметр mode може приймати одне із значень, призначуване в залежності від мети відкриття файлу, або комбінацію цих значень, отриману з використанням операції " або " , тобто "|" . Операції мають вигляд:
ios :: app файл (потік) відкривається для додавання в кінець("а");
ios :: in файл відкривається для читання (" r ") ;
ios :: out файл відкривається для запису ("w ");
ios :: ate відкрити файл і установити покажчик потоку на кінець файлу;
ios :: binary відкрити файл у двійковому режимі ;
ios :: trunc відкрити файл і видалити зміст файлу ;
ios :: nocreate відкрити існуючий файл, якщо він не існує
операцію завершити повідомленням;
ios :: noreplace якщо файл існує видати повідомлення про помилку, за винятком випадків пошуку кінця або файлу додавання у файл.
Розглянемо деякі приклади записів функцій відкриття файлу :
#include <fstream.h>
Int main ( )
{
fstream fp; // опис файлової змінної;
// відкривається файл myfile.dat для запису, тобто створюється новий файл;
fp. open ( " a : \ cpp \ myfile.dat " , ios :: out)
// відкривається раніше створений файл file2.dat для читання даних;
fp.open (" c : \ vp \ file2.dat ", ios :: in );
// відкривається файл для читання або запису з використанням
// двійкового режиму;
fp .open (" myfile " , ios :: out | ios :: in | ios :: binary);
return 0;
}
Файлова змінна fp повинна бути попередньо описана як об'єкт класу fstream або ofstream. Якщо під час відкриття файлу відбувається помилка, то завжди fp = 0, тобто файлова змінна дорівнює нулю. Це використовується для визначення результату відкриття файлу в такий спосіб :
#include <fstream.h>
main ( )
{
ofstream . fp;
fp.open ( " Filename " , ios :: app); // Додати у файл
if (!fp )
{
cout << "Помилка відкриття файлу " << endl;
exit (0);
} // Вихід із програми
else
{
// Текст програми роботи з файлом
}
}
Для організації циклу з метою перегляду усього файлу, можна використовувати оператор циклу у вигляді:
while ( ! fp.eof ( ))
{……………
…………...}
Приклад 6.1 Записати у файл п'ять прізвищ.
//P5_1.CPP запис у файл п'яти прізвищ
#include < fstream .h >
ofstream fp;
int main ( )
{
fp.open ( " a : \ Myfile " , ios :: out); // Створення нового файлу
fp << " Авдєєв А.И. " << endl;
fp << " Бобрів А.П. " << endl;
fp << " Кузьмін И.В. " << endl;
fp << " Попов Р.Л. " << endl;
fp << " Яковлев Ю.Т. " << endl;
fp. close ( ); // Закриття файлу
}
Відкривати файли можна й інакше, наприклад, використовуючи класи ifstream для читання з файлу (тобто введення) і ofstream для запису у файл :
ifstream in ( " Namefile "); // відкриття файлу для читання з файлу
ofstream out ( " Namefile2 "); // відкриття файлу для запису у файл ,
де in і out файлові змінні відповідного класу.
Приклад 6.2 Копіювання одного текстового файлу в інший файл.
// P5_2.CPP копіювання текстового файлу file1 у файл file2
#include <iostream.h>
#include <fstream.h>
void main ( )
{
ifstream in ( ”file1") ;
ofstream out ( "file2") ;
char st [80];
while ( ! in.eof ( ) )
{
in .getline ( st, 80 ) // in об'єкт ifstream
out << st << endl; // запис st у файл file2
cout << st << endl; // виведення st на екран
}
in.close();
out.close();
}
Конструктори ifstream і ofstream можуть бути записані у вигляді: ifstream in (const char *name, int mode = ios :: in,
int prot = filebuf :: penprot);
тобто ці конструктори можуть включати ті ж аргументи, що і open.
Приклад 6.3 Записати у файл задану матрицю matr ( 2, 4) построково.
//P5_3.CPP запис у файл матриці построково
#include <iostream.h>
#include <fstream.h>
void main ( )
{
int mas [4], matr [2][4];
int i, j;
ofstream out (" filemat " );
for ( i = 0; i < 2; i++)
for ( j = 0; j < 4; j++ )
{
cin >> mas [j];
out << mas[j]<<” “;
}
out . close( );
ifstream in ("filemat ”);
for ( i = 0; i < 2 ; i++)
{
for ( j = 0 ; j < 4; j++)
in>> matr [ i ] [ j ] ; // Запис масиву в рядок матриці
}
in . close ( );
for ( i = 0; i < 2 ; i++ ) // Виведення матриці на екран
{
cout << endl ;
for ( j = 0; j < 4 ; j++)
cout << matr [i] [j];
}
}
6.3 Контрольні питання
1. Чим файл відрізняється від масиву ?
2. За допомогою якої функції можна розпізнавати кінець файлу ?
3. Як описується файлова змінна ?
4. Який порядок створення файлу ?
5. Які засоби відкриття файлів ?
6. Які параметри можуть використовуватися як компоненти файлу ?
6.4 Індивідуальні завдання
1. Створити файл, що містить список студентів групи з наступними характеристиками : адреса, місце роботи батьків , вік і забезпечити виведення інформації про студентів за заданим прізвищем .
2. Створити файл, що містить список студентів з їх середнім балом на сесії . Забезпечити читання файлу і видачу прізвищ встигаючих студентів.
3. Створити файл, що містить коротку бібліографічну інформацію о прочитаних вами книгах. Забезпечити виведення інформації про всі книги, видані у заданому діапазоні років.
4. Створити файл, що містить наступну інформацію: прізвище, рік народження, стать. Забезпечити виведення прізвищ за заданим роком народження.
5. Створити файл, що містить номери потягів і їхні маршрути . Забезпечити видачу інформації про маршрут за введеним номером потяга.
6. Створити файл, що складається з масиву чисел X(20). Забезпечити читання цього файлу і заповнення матриці Y(4,5).
7. Створити файл , що містить наступну інформацію: прізвище, номер домашнього телефону. Забезпечити видачу номера телефону за введенням прізвища.
8. Створити файл, що містить коротку бібліографічну інформацію про прочитані вами книги. Забезпечити виведення інформації про книгу за заданим прізвищем автора.
9. Створити файл, що містить англійські слова і їх переклад. Забезпечити переклад введеного англійського слова , що входить у словник.
10. Створити файл, що містить список власників автомобілів із указівкою кольору, номеру й адреси власника. Вивести за запитом про колір прізвища власників автомобілів і дані про машини.
11. Створити файл, що містить список студентів з їх оцінками за результатами сесії. Забезпечити читання файлу і видачу прізвищ студентів, що мають середній бал не нижче заданого.
12. Створити файл, що містить слова. Забезпечити виведення слів, що починаються з великої літери.
13.Створити файл, що містить список товарів з наступними характеристиками: назва, ціна, срок придатності. Забезпечити виведення інформації про товари, найбільша ціна яких не перевищує заданої за запитом.
14. Елементами файлу є відомості про успішність. Скільки в групі відмінників і двієчників?
15. Створити файл, що містить розклад роботи лікаря. Вивести дні тижня, у які лікар працює до обіду.
16. Створити файл, що містить коротку інформацію про пацієнтів клініки. Вивести інформацію про пацієнтів за зменщенням року народження.
17. Створити файл , що містить список мешканців будинку з указівкою прізвища, місця роботи і року народження. Вивести за запитом про прізвище мешканця.
18. Створити файл, що містить розклад занять студентів групи. Забезпечити виедення розкладу по введеному дню тижня.
19. У тексті програми мовою C++ підрахувати кількість операторів "cin " і " if " .
20. Створити файл на диску, що містить деякий текст. Вивести слова тексту в зворотньому порядку.
21. Створити файл на диску, що містить деякий текст. Вивести слова тексту , що починаються з літери "а".
22. У тексті програми мовою С++ (ім'я файлу на диску ввести за запитом) підрахувати кількість операторів, пам'ятаючи, що кожен оператор закінчується ";".
23. Створити файл, що містить список прізвищ. Забезпечити виведення прізвищ, що починаються з літери, що вводиться за запитом.
24. У файл із прізвищами студентів вставити нове прізвище після заданого прізвища.
25. У файлі вказані прізвища переставити місцями і вивести результат на екран.
ЛІТЕРАТУРА І ДЖЕРЕЛА
1. Подбельский В. В. Язык Си++ : учебное пособие. 5 - е изд. - М.: Финансы и статистика, 2000. - 560 с.
2. Проценко В. С. та ін. Техніка програмування мовою Сі: Навч. посібник / В. С. Проценко, П. И. Чаленко, А. Б. Ставровський. - К. Либідь, 1993. - 224 з
3. Програмування на С++. Учебное пособие / В. П. Аверкин, А. И. Бобровский, В. В. Веснин, В. Я. Радушинский, А. Д. Хомоненко; Под ред. проф. А. Д. Хомоненко СПБ: КОРОНА принт,1999 256 с., мул.
4. Харви Дейтел, Пол Дейтел Как программировать на C++: Пер с анг. М. ЗАО «Издательство БИНОН», 1998р. 1024с., ил.
1. Організація введення і виведення в програмах. вирішування задач із простою змінною………….....………………………………………………………………4
2. Вирішування задач з використанням одновимірних і двовимірних масивів..24
3. Виріщування задач з використанням даних символьноготипу………………46
4. Вирішування задач з використанням даних типу структура .........……......…67
5. Використання функцій при розробці програм ...………….…………….........77
6. Робота з файлами ..……………………………………………………………...95
Література і джерела ……………………………………………………..………102
Навчальне видання
Методичні вказівки до виконання лабораторних та практичних робіт з курсів “Інформатика” для студентів напряму підготовки 6.170103 - «Управління інформаційною безпекою».
Укладачі: Сінельнікова Т.Ф
Відповідальний за випуск Е. П. ПутятІн
Редактор
План , поз.16
Підп. до друку Формат 60х84 1/16
Умов. друк. арк. 4,8. Облік вид. арк. 4,2. Вид.№32.
Тираж 120 прим.
Зам.№___ .Ціна договірна.
ХHУРЭ. 61726 Харків, просп. Леніна, 14.
Надруковано в учбово-виробничому видавничо-поліграфічному центрі ХHУРЕ
61726 Харків, просп. Леніна, 14.