Масиви та вказівники в С++ Проф. Куссуль Н. М. 1
Масиви: загальні відомості Масив – тип даних, який використовується для представлення послідовності однорідних значень. Елементи масиву займають одну неперервну область пам’яті комп’ютера і розміщені послідовно один за одним. В С++ можливі масиви будь-яких типів: n n n базових користувацьких масиви масивів тощо 2
Масиви: загальні відомості При оголошенні масиву виділяється пам’ять, починаючи з базової адреси. Ім’я масиву є постійним вказівником, який ініціалізований цією базової адресою. 3
Приклад int mas 1[492]; // зовнішній масив з 492 елементів void main(void) { double mas 2[250]; // масив з 250 чисел типу double static char mas 3[20]; //статичний рядок з 20 символів extern mas 1[]; //зовнішній масив, розмір вказано вище int mas 4[2][4]; // двовимірний масив з чисел типу int } 4
Індексування Нумерація елементів масиву починається з нуля і закінчується n-1 (n - кількість елементів масиву). Доступ до окремого елементу масиву організується з використанням номера цього елементу, або індексу. Нехай int i, a[n]; Доступ a[цілий_вираз]; 5
Індексування Значення індексу поза діапазону викликає помилку виконання. Така ситуація наз. перевищення меж масиву або вихід індексу за межі. Ефект від такої помилки в С++ залежить від системи і може бути несподіваним! 6
Ініціалізація масиву означає присвоєння початкових значень його елементам при оголошенні. Масиви можна ініціалізувати списком значень або виразів, відокремлених комою, розташованих у фігурних дужках: n int days[12] = {31, 28, 31, 30, 31, 30, 31}; 7
Ініціалізація масиву Масив також можна ініціалізувати списком без зазначення в дужках довжини масиву. При цьому масиву присвоюється довжина за кількістю ініціалізаторів: n n char code[] = {'a', 'b', 'c'}; в даному прикладі масив code матиме довжину 3 8
Динамічний масив Масив, розмірність якого стає відомою в процесі виконання програми. В С++ для роботи з динамічними об’єктами використовують спеціальні операції new і delete n n n за допомогою операції new виділяється пам’ять під динамічний об’єкт (який створюється в процесі виконання програми) якщо за допомогою операції new неможливо виділити потрібний об’єм пам’яті, то результатом операції new є 0 за допомогою операції delete створений об’єкт видаляється з пам’яті 9
Приклад Нехай розмірність динамічного масиву вводиться з клавіатури. Спочатку необхідно виділити пам’ять під цей масив, а потім створений динамічний масив треба видалити. n int n; cin>>n; // n — розмірність масиву, вводиться з клавіатури int* mas = new int[n]; // виділення пам’яті під масив. . . delete[] mas; // звільнення пам’яті 10
Багатовимірні динамічні масиви Двовимірний масив: створення n n mas=new int[n][k]; // Невірно! Помилка! int** a; //a - вказівник на масив вказівників на рядки a=new int* [n]; //виділення пам’яті для масиву вказівників на n рядків for(int i=0; i
Багатовимірні динамічні масиви Двовимірний масив: знищення n for(int i=0; i
Передача масивів у функції Масиви можуть бути параметрами функцій, і функції як результат можуть повертати вказівник на масив. При використанні масивів як параметрів функції виникає необхідність визначення в тілі функції кількості елементів масиву, що є аргументом при звертанні до функції. 13
Передача масивів у функції При роботі з рядками (масивами типу char[]), проблема розв'язується просто, оскільки останній елемент рядка має значення ' '. Наприклад n int length(char c[]) { int i; for(i=0; ; i++) if (c[i]==' ') break; return i; } 14
Передача масивів у функції Якщо масив-параметр функції не є символьним рядком, то необхідно або використовувати масиви з заздалегідь відомим числом елементів, або передавати розмір масиву за допомогою додаткового параметра. 15
Передача масивів у функції Передача з відомим числом елементів int sum(float x[5]) { float s=0; for(int i=0; i<5; i++) s=s+x[i]; return s; } 16
Передача масивів у функції Використання додаткового параметра float max(float a[], int n) { float m=a[0]; for(int i=1; i
Передача масивів у функції: багатовимірні масиви Особливістю мови С++ є несамовизначеність масивів => за іменем масиву неможливо довідатися про його розмірність і розміри за кожним виміром. Крім того, у С++ багатовимірні масиви не визначені. Наприклад: n n n якщо оголошений масив float d[3][4][5], то це не тривимірний, а одномірний масив d, що включає три елементи, кожний з який має тип float [4][5] в свою чергу, кожний з чотирьох елементів є типу float [5] і, відповідно, кожний з цих елементів є масивом з п'яти елементів типу float. 18
Передача масивів у функції: багатовимірні масиви При передачі масивів як параметрів через заголовок функції варто враховувати, що передавати масиви можна тільки з однією невизначеною границею мірності (ця мірність повинна бути найлівішою). 19
Передача масивів у функції: багатовимірні масиви #include
Передача масивів у функції: багатовимірні масиви #include
Взаємозв’язок між масивами та вказівниками Ім'я масиву являє собою константний (фіксований) вказівник на адресу першого (з індексом 0) елемента масиву. Вказівник – це змінна, яка приймає в якості значень адресу. 22
Вказівники Вказівник - це символічне представлення адреси. Він використовується для непрямої адресації змінних і об'єктів. В мові С++ є операція визначення адреси — &, за допомогою якої визначається адреса комірки пам’яті, що містить задану змінну. Наприклад, n якщо vr — ім’я змінної, то &vr — адреса цієї змінної. 23
Вказівники В С++ також існують і змінні типу вказівник. Значенням змінної типу вказівник є адреса змінної або об'єкта. Нехай змінна типу вказівник має ім'я ptr, тоді в якості значення їй можна присвоїти адресу за допомогою наступного оператора: n int vr; int* ptr; ptr = &vr; 24
Вказівники В мові С++ при роботі з вказівниками велике значення має операція непрямої адресації — *. Операція * дозволяє звертатися до змінної не напряму, а через вказівник, який містить адресу цієї змінної. Ця операція є одномісною і має асоціативність зліва направо. n NB Цю операцію не слід плутати з бінарною операцією множення. Нехай ptr — вказівник, тоді *ptr — це значення змінної, на яку вказує ptr. 25
Приклад int a = 5; // оголошення змінної int* p = &a; // p вказує на а int& ref_a = a; // псевдонім для а *p = 7; // значення за адресою p буде дорівнювати 7, тобто а = 7 а = *р + 1; // а стане дорівнювати 8 NB будь-які зміни а рівносильне зміні ref_a! 26
Вказівник і масиви Нехай int mas[4][2]; int *ptr; Тоді вираз ptr=mas вказує на перший стовпець першого рядка матриці. Записи mas і &mаs[0][0] рівносильні. Вираз ptr+1 вказує на mas[0][1], далі йдуть елементи: mas[1][0], mas[1][1], mas[2][0] і т. д. ; ptr+5 вказує на mas[2][1]. ptr+1 ptr+2 mas[0][0] mas[0][1] mas[1][0] ptr+3 ptr+4 ptr+5 mas[1][1] mas[2][0] mas[2][1] 27
Посилання (reference) являє собою видозмінену форму вказівника, яка використовується в якості псевдоніму (другого імені) змінної. У зв’язку з цим посилання не потребують додаткової пам’яті. Для визначення посилання використовують символ & (амперсант), який ставиться перед змінноюпосиланням. Змінні типу посилання можуть використовуватися для наступних цілях: n n n замість передачі у функцію об’єкта за значенням; для визначення конструктора копії; для перевантаження унарних операцій; 28
Приклад #include
Приклад. Функція з параметром-посилання. #include