Масиви покажчиків

Подібно до інших змінних, покажчики можна групувати в масиви, кожен з елементів яких містить адресу рядка масиву да­них у пам’яті. Такий спосіб дозволяє зберігати дані з рваними краями, наприклад, деяку текстову інформацію (див. рис. 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];.

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *