Device . put (char_var); , 3 страница
р + n ; ,
де n— ціле значення, а р — покажчик.
Цей вираз визначає область об'єкта, що займає n -те місце після об'єкта, на який указує р, при цьому nавтоматично збільшується на коефіцієнт,що дорівнює відповідній довжині об'єкта. Наприклад , якщо intзаймає 4 байти , то цей коефіцієнт дорівнює чотирьом.
Допускаються також порівняння покажчиків, що вказують на елементи одного масиву.
Наприклад, якщо р1< p2,тор2 - р1+1 — це число елементів масиву від р1дор2включно.
Таким чином, з покажчиками допускаються наступні операції :
— присвоювання значення одного покажчика іншому;
— додавання і вирахування покажчиків і даного цілого типу ( р+5 );
—порівняння двох покажчиків, що посилаються на елементи одного масиву;
— присвоювання покажчику нуля і порівняння з нулем.
Інші операції з покажчиками заборонені.
Для покажчика дозволяються вирази вигляду:
р1 = mas;або р++ ,
тут р— покажчик , mas — масив.
Розглянемо демонстраційні приклади програм роботи з покажчиками.
Приклад 2.4Обчислити середнє значення додатних елементів одновимірного масиву.
Наведемо кілька варіантів програмної реалізації цієї задачі.
// P2_7.CPP — обчислення середнього значення
// додатних елементів масиву
//програма без використання покажчиків
#include < iostream>
Using namespace std;
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>
Using namespace std;
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>
Using namespace std;
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>
Using namespace std;
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>
Using namespace std;
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>
Using namespace std;
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 == 0)
mat[i][j] = mat[i][j] + 5;
cout << mat [i][j] << " ";
}
cout << endl; //Переведення рядка при виведенні матриці
}
}
Другий варіант програмної реалізації —матриця описана як масив покажчиків.
//P2_13.CPP — матриця описана як масив покажчиків:
#include < iostream>
Using namespace std;
Main ( )
{
int і, j, *pm[2];
cout << "Введіть матрицю "<< endl;
for ( i = 0; i < 2; i++)
for ( j = 0; j < 3; j++)
cin >> *( pm[i] + j );
cout << " Матриця МАТR "<< endl;
for ( i = 0; i < 2; i++)
{
for ( j = 0; j < 3; j++)
{
if ( *(pm[i] + j) %2 == 0 )
*( 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;
2.6 Контрольні питання
1. Що таке масив?
2. Як здійснюється опис масивів у програмі?
3. Як вибирається елемент масиву з пам'яті?
4. Які ще оператори мови C++ можна використовувати для введення елементів масиву в пам'ять комп'ютера?
5. Скільки циклів треба використовувати для введення, виведення і перебору елементів матриці?
6. Як звернутися до довільного елемента масиву?
7. Які обмеження існують у C++ на розмір і розмірність масивів?
8. Як вивести на друк матрицю в природному вигляді?
2.7. Варіанти індивідуальних завдань
У запропонованих нижче варіантах завдань конкретні значення масивів задаються довільно.
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 ВИРІШУВАННЯ ЗАДАЧ З ВИКОРИСТАННЯМ ДАНИХ СИМВОЛЬНОГО ТИПУ
3.1 Ціль роботи
Вивчення засобів опису символьних типів даних і використання структур для обробки даних.
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 ;
¾ виконання перепризначення виведення на принтер за допомогою операторів
ofstream prn ("PRN");
prn << " Виведення до роздруку повідомлення "<< endl;
prn << name1 << name2 ... <<endl;
Такий порядок дій застосовується при компіляції як задача DOS і нижче приведена його програмна реалізація .
Приклад3.1 Вивести дані (прізвище й ім'я) на принтер.
//P3_1.СPP — виведення прізвища й імені на принтер
#include < fstream>
#include < iostream>
Using namespace std;
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>
#include < iostream>
Using namespace std;
#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 Рядки як символьні масиви