Подібно до інших змінних, покажчики можна групувати в масиви, кожен з елементів яких містить адресу рядка масиву даних у пам’яті. Такий спосіб дозволяє зберігати дані з рваними краями, наприклад, деяку текстову інформацію (див. рис. 6.5) Масив з «рваними» краями схожий на двовимірну таблицю, рядки якої можуть мати різну довжину. Використання масиву покажчиків (char *fio[ ]) для збереження рядків дозволяє заощаджувати пам’ять, а процес обробки рядків виконується значно швидше, бо змінюються тільки покажчики, а не вміст рядків.
Приклад 6.8. Заданий масив з рваними краями (див. рис. 6.5) Навести програмну реалізацію виведення такої інформації з використанням масиву покажчиків.
// P6_8.CPP — использование массива указателей #include <iostream.h> #include <conio.h> main ( ) { char *fio[ ] = { "Петренко", "Головко", "Корж", "Куц", "Юшко", "Плющ" }; // инициализация массива указателей int str; for (str = 0; str <=5; str++) cout << " stroka " << (str + 1) << " = " << *(fio + str) << endl; getch(); // для задержки экрана вывода результата }
Результати виконання програми:
stroka 1 = Петренко
stroka 2 = Головко
stroka 3 = Корж
stroka 4 = Куц
stroka 5 = Юшко
stroka 6 = Плющ
Нa рис. 6.5 представлено зв’язок масиву покажчиків char *fio[ ] з відповідними текстовими рядками.
Особливістю масиву покажчиків є те, що кожний з його елементів може вказувати на масив довільної довжини. Iснуе можливість записати двовимірний масив чисел і як матрицю, і як одновимірний масив покажчиків.
int matr[5][7];
або int *pmt[5];.
При цьому двовимірний масив розглядається як одновимірний масив рядків, кожен елемент якого — це теж масив стовпцiв, тобто масивмасивів, тому індексування елементів матриці записуется у вигляді mas[i][j].
Звернення до елемента mas [i][j] може здійснюватися так:
*(pm[i] +j)
або *(*(рm + і) + j) .
Приклад 6.9. Сформувати матрицю цілих чисел С(5,5), елементи якої обчислюються за формулою Сij = i+j. Підрахувати добуток елементiв, розташованих нижче побічної діагоналі, та обнулити ці елементи. Вивести на екран елементи, розташовані в трикутниках нижче головної та вище побічної діагоналей.
Перший варіант програмної реалізації даної задачі (див. Р6_10_1.СРР) передбачає, що матриця описується явним способом і робота ведеться з її елементами.
// Р6_9_1.СРР — программа без использования указателей #include <iostream.h> #include <conio.h> const int n = 5; int main() { int i, j, C[n][n]; int Pr; // Pr — переменная для подсчета произведения //------------------- формирование матрицы С[n][n] cout << "------ Матрица С[n][n]: \n"; for (і = 0; і < n; i++) { for (j = 0; j < n; j++) { C[i][j]=i+j; cout << C[i][j] << " " ; } cout << endl; } /* вычисление произведения (Pr) элементов ниже побочной диагонали и их последующее обнуление */ Pr = 1; //начальное значение Рr for (і = 0; і < n; i++) for (j = n - і; j < n; j++) { Pr*= C[i][j]; C[i][j] = 0; } //-------------- вывод па экран полученных результатов cout << "\n Произведение ниже побочной диагон. = " <<Рг << endl; cout << "\n-------- Преобразованная матрица \n"; for (і = 0; і < n; i++) { for (j = 0; j < n; j++) cout << C[i][j] << " "; cout << endl; } //---------------------- вывод элементов ниже главной диагонали cout << "\n Элементы ниже главной диагонали "; for (і = 0; і < n; i++) { for (j=0; j<n; j++) if (j < i) cout << C[i][j] << " "; else cout << " " ; cout << endl; } //--------------------- вывод элементов выше побочной диагонали cout << "\n Элементы выше побочной диагонали \n"; for (і = 0; і < n; i++) { for (j = 0; j < n; j++) if (j < n-1-i) cout << C[i][j] << " "; else cout << " "; cout << endl; } getch(); return 0; }
Результати обчислень:
——–Матрица C[n]|n]:
0 1 2 3 4
1 2 3 4 5
2 3 4 5 6
3 4 5 6 7
4 5 6 7 8
Произведение ниже побочной диагон. = 52920000
——– Преобразованная матрица
0 1 2 3 4
1 2 3 4 0
2 3 4 0 0
3 4 0 0 0
0 0 0 0 0
Элементы ниже главной диагонали
1
2 3
3 4 0
4 0 0 0
Элементы выше побочной диагонали
0 1 2 3
1 2 3
2 3
3
Другий варіант програмної реалізації (див. Р6_9_2.СРР) використовує масив покажчиків:
// Р6_9_2.СРР — формирование и обработка матрицы //-------------- используется массив указателей #include <iostream.h> #include <conio.h> const int n = 5; int main() { int i, j, Pr, C[n][n], *pm[n]; //---------------- инициализация массива указателей for (і = 0; і < n; і++) pm[i] = &C[i][0]; //--------------- формирование матрицы С[n][n] cout << " Матрица C[n][n]"<< endl; for (i = 0; і < n; i++) for(j = 0; j < n; j++) *(pm[i] + j) = i+j; //------------------ вывод матрицы for (i = 0; i < n; i++) { for (j = 0; j < n; j++) cout << *(pm[i] + j) << " "; cout << endl; } /* вычисление произведения (Pr) элементов ниже побочной диагонали и их последующее обнуление */ Pr = 1; for (i = 0; i < n; i++) for (j = n-i; j < n; j++) { Pr*=*(pm[i] + j); *(pm[i]+j) = 0; } //------------ вывод на экран полученных результатов cout << endl <<" Произведение ниже побочной диагон. = " << Pr << endl; cout << endl << " Преобразованная матрица " << endl; for (і = 0; і < n; i++) { for (j = 0; j < n; j++) cout << *(pm[i] + j) << " "; cout << endl; } //----------------- вывод элементов ниже главной диагонали cout << endl << " Элементы ниже главной диагонали"; for (і=0; і < n; і++) { for (j = 0; j < n; j++) if (j < i) cout << *(pm[i] + j) << ' '; else cout << " "; cout << endl;} cout << endl; //------------ вывод элементов выше побочной диагонали cout << endl << " Элементы выше побочной диагонали " << endl; for (і = 0; і < n; і++) { for (j = 0; j < n; j++) if (j < n-1-i) cout << *(pm[i] +j) << ' '; else cout << " "; cout << endl; } getch(); return 0; }
У розглянутій програмі для виведення матриці можна використати інший вигляд оператора виведення, наприклад:
cout << ( (j = = 0) ? ‘\t’: ‘ ‘)<< *(pm[i] +j) << ((j= =n)? ‘\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 [і] + j);
cout << *(*(mat + і) + j);.
Приклад 6.10. Задана матриця aij (i = 1…n, j = 1…m) n = 3, m = 4, необхідно її парні елементи переписати до масиву b, а непарні — до масиву с.
Алгоритм розв’язання цієї задачі наведено у прикладі 1.6
/* Р6_10.СРР — формирование массивов четных и нечетных элементов */ // использование имени массива как указателя на его начало #include <iostream.h> #include <conio.h> const int n = 3, m = 4; void main () { int a[n][m], b[m*n], c[m*n], i, j, kc = 0, kn = 0; // kc и kn — счетчики подсчета четных и нечетних элементов //-------------------- ввод исходной матрицы а[n][m] cout << " Vvod massiva a[n][m] " << endl; for (і = 0; і < n; i++) for (j = 0; j < m; j++) cin >> *(*(a+i)+j); //------------ формирование массивов b[ ] и c[ ] for (i = 0; і < n; i++) for (j = 0; j < m; j++) if (*(*(a+i)+j)%2 == 0) *(b+kc++) = *(*(a+i)+j); else *(c+kn++) = *(*(a+i)+j); //—-------- вывод массива b[] — четных элементов cout << endl << "massiv chetn. elementov — b[ ] " << endl; for (і = 0; і < kc; i++) cout << *(b+i) << " "; cout << endl; //----------------- вывод массива c[ ] — нечетных элементов cout << endl << "massiv nechetn. elementov — c[ ]" << endl; for (і = 0; і < kn; i++) cout << *(c+i) << " "; cout << endl; //------------------ вывод исходной матрицы a[n][m] в естественном виде cout << endl << "ishodny massiv"; for (і = 0; і < n; і++) { cout << endl; for (j = 0; j < m; j++) cout << *(*(a+i)+j) << " "; } getch(); }
Результати обчислень:
Vvod massiva a[n][m]
8 2 4 -1
6 1 0 -5
2 9 3 -1
massiv chetn. elementov — b[ ]
8 2 4 6 0 2
massiv nechetn. elementov — c[ ]
-1 1 -5 9 3 -1
ishodny massiv
8 2 4 -1
6 1 0 -5
2 9 3 -1.
У C++ можна описати змінну, що має тип «покажчик на покажчик». Ознакою такого типу є повторення символа «*» при описі змінної, тобто int **pmt;.
Пам’ять для такої змінної не виділяється. Її треба привести до відповідного масиву. При описі покажчик на іпокажчик можна ініціювати:
int х = 20;
int *px1 = &х;
int **рх2 = &рх1;
int ***рхЗ = &рх2;.
Доступ до змінної х здійснюється одним з трьох, способів:
*рх1;
**px2;
***рхЗ;.
Для доступу до пам’яті через покажчики на покажчики використовуються як символи «*», так і індекси. Наприклад, іеквівалентими будуть такі посилання на змінну х:
*px1; //рx1 [0];
**рх2; //рх2 [0][0];
***рхЗ; //рхЗ [0][0][0];.