Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Вказівники та посилання.docx
Скачиваний:
0
Добавлен:
01.04.2025
Размер:
857.42 Кб
Скачать

9. Подвійний вказівник

Інший спосіб деактивації дії модифікатора const це використаня операторів динамічної роботи з типами.

С++ дозволяє оголошувати вказівник на вказівник (подвійний вказівник). Загальний синтаксис має вигляд

тип** ім’я вказівника;

Операція подвійного знаходження адреси &&, яка інтуїтивно напрошується стосовно подвійного вказівника, є недопустимою, тобто наступний код є неправильним

int i = 1;

int **j = &&i; // недопустима операція

Розіменування подвійного вказівника до типованої зміної здійснюється через операцію **. Наведемо приклади

а) int i=5;

int* j=&i;

int** z=&j;

**z=4; // розіменування подвійного вказівника

Приклад 11

#include <windows.h>

#include <clocale>

#include <iostream>

void main()

{

setlocale (LC_CTYPE,"rus");

int i=5;

std::cout<< "Початкове значення i: "<< i<<std::endl;

int* j=&i;

int** z=&j;

**z=4; // розіменування подвійного вказівника

std::cout<< "Модифiковане значення i: "<<i<<std::endl;

system("pause");

}

Скомпілюйте наведений приклад.

б) int i;

int* j=&i;

int** z;

z=&j;

**z=4; // розіменування подвійного вказівника

Приклад 12

#include <windows.h>

#include <clocale>

#include <iostream>

void main()

{

setlocale (LC_CTYPE,"rus");

int i;

int* j=&i;

int** z;

z=&j;

**z=4; // розіменування подвійного вказівника

std::cout<< "Значення i: "<<i<<std::endl;

system("pause");

}

Скомпілюйте наведений приклад.

Зазначимо, що більше двох рівнів непрямої адресації, в переважній більості випадків не використовується. Проте різні компілятори дають різну кількість рівнів організації багаторівневих ланцюжків непрямої адресації. Так, наприклад Visual C++ 6.0 дозволяє організовувати до 1010 рівнів, а Turbo C++ - 70 рівнів.

10. Вказівники і масиви

В С++ ім'я масиву є адресою його першого елемента, тобто:

char ach[30]; // тут ach є адресою &ach[0];

Це робить простою організацію вказівників на масиви даних

int ach[10];

int* j;

// перший варіант організації вказівника j на масив achArray

j=&ach[0];

// другий варіант організації вказівника j на масив achArray

j=ach;

Наприклад у вас є вказівник на масив цілих чисел (int A[]). Вказівник спочатку буде вказувати на перше значення в масиві як показує наступний приклад:

Приклад 13

#include <windows.h>

#include <clocale>

#include <stdio.h>

void main()

{

setlocale (LC_CTYPE,"rus");

int A[3]={10, 20, 30};

int *p;

p = &A[0];

printf("p вказує на значення: %d\n", *p);

system("pause");

}

Скомпілюйте наведений приклад.

Приклад 14

#include <windows.h>

#include <clocale>

#include <stdio.h>

void main()

{

setlocale (LC_CTYPE,"rus");

int A[3]={10, 20, 30};

p = A;

printf("p вказує на значення: %d\n", *p);

system("pause");

}

Скомпілюйте наведений приклад.

Розглянемо організацію доступу до елементів масиву через вказівник. Цей процес складається з двох етапів:

1) ініціалізація вказівника адресою першого чи останнього елемента масиву;

2) використання циклічного оператора для доступу до елементів масива або маніпуляції адресою, яку містить вказівник. Зокрема, якщо j=&ach[0], то наступні звертання до і-го елемента масиву ach є рівносильними

ach[i] = j[i] = *(j+i);

Зауважимо: хоча операції * i & мають найвищий пріоритет, проте операція *j++ приведе до значення елемента масиву з індексом збільшеним на одиницю (читається даний вираз справа наліво). Тобто, при умові j=&ach[0]

*j++ = ach[1] = *(j+1) = *(j++).

Для того щоб перемістити вказівник до наступного елементу масиву, ми можемо написати p++. Ми також можемо, як деякі з вас могли вже здогадатися, нанисати p + 2, що перемістить вказівник відразу на 2 елементи. Потрібно бути обережним з верхньою межею масиву (в даному випадку це 3 елементи), тому що компілятор не може перевірити чи вийшли ви за межі масиву, використовуючи вказівники. Ви легко можете отримати повний збій системи якщо будете не акуратні. Ось ще один приклад. На цей раз він показує три значення які ми встановили:

Приклад 15

#include <windows.h>

#include <clocale>

#include <stdio.h>

void main()

{

setlocale (LC_CTYPE,"rus");

int A[3]={10, 20, 30};

int *p;

p = A;

for (int і=0;і<3;і++)

{

printf("p вказує на значення: %d\n", *p);

p++;

}

system("pause");

}

Скомпілюйте наведений приклад.

Для того щоб збільшити на одиницю значення елемента масиву, треба записати (*j)++.

Приклад 16

#include <windows.h>

#include <clocale>

#include <stdio.h>

void main()

{

setlocale (LC_CTYPE,"rus");

int A[3]={10, 20, 30};

int *p;

p = A;

for (int і=0;і<3;і++)

{

(*p)++;

printf("p вказує на значення: %d\n", *p);

p++;

}

system("pause");

}

Скомпілюйте наведений приклад.

Ми також можемо рухати вказівник в будь-яку сторону, так p - 2 це 2 елементи від того місця куди вказує вказівник. Переконайтесь, що ви збільшуєте та зменшуєте значення вказівника, а не значення змінної, на яку він вказує. Даний метод використання вказівників і масивів найбільш корисний при використанні циклів, таких як for чи while.

Відмітимо також , що якщо ми маємо вказівник на змінну, наприклад int* p, ми можемо розглядати його як масив. Наприклад, p[0] еквівалентне *p; а p[1] еквівалентне *(p + 1).

Доступ до матриці (двомірного масиву) організовується як масив вка­зівників на рядки, або як вказівник на вказівник, наприклад

Приклад 17

#include <windows.h>

#include <clocale>

#include <iostream>

#include <conio.h>

void main()

{

setlocale (LC_CTYPE,"rus");

const unsigned int row=10; //unsigned - невід'ємне значення

const unsigned int col=10;

float arfl[row][col]; //оголошення матриці

float* p1[row]; //оголошення масиву вказівників

float** p2=p1; //оголошення подвійного вказівника

int i,j; //оголошенні лічильників циклів

for (i=0; i<row; i++) //ініціалізація масиву елементів

{

for (j=0; j<col; j++)

arfl[i][j]=float(i+j); // матриці

p1[i]=&arfl[i][0]; // вказівників

}

float Suma=0,Suma_p1=0,Suma_p2=0;

for (i=0; i<row; i++) // обчислення суми елементів масиву

for (j=0; j<col; j++)

{

Suma+=arfl[i][j]; // через індентифікатор матриці

Suma_p1+=*(*(p1+i)+j);// через масив вказівників

Suma_p2+=*(*(p2+i)+j);// через подвійний вказівник

}

std::cout<<"Сума елементiв матрицi розрахована чеоез:"<<"\n";

std::cout<<" -iндентифiкатор масиву: "<<Suma<<"\n";

std::cout<<" - подвiйний вказiвник: "<<Suma_p2<<"\n";

std::cout<<" - масив вказiвникiв: "<<Suma_p1<<"\n";

system("pause");

}