Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
+ООП_Навч_посібник.doc
Скачиваний:
8
Добавлен:
01.07.2025
Размер:
6.58 Mб
Скачать

6.4.2. Індексування покажчика

Як було показано вище, можна отримати доступ до масиву, використовуючи арифметичні дії над покажчиками. Цікаво, що у мові програмування C++ покажчик, який посилається на масив, можна індексувати так, як би це було ім'я масиву (це свідчить про тісний зв'язок між покажчиками і масивами). Відповідний такому підходу синтаксис забезпечує альтернативу арифметичним операціям над покажчиками, оскільки він є дещо зручнішим у деяких ситуаціях. Розглянемо конкретний приклад.

Код програми 6.7. Демонстрація індексування покажчика подібно до індексування масиву

#include <iostream> // Для потокового введення-виведення

#include <cctype> // Для роботи з символьними аргументами

using namespace std; // Використання стандартного простору імен

int main()

{

char strMas[20] = "Я тебе люблю";

char *p;

int i;

p = strMas;

// Індексуємо покажчик.

for(i=0; p[i]; i++) p[i] = toupper(p[i]);

cout << p; // Відображаємо рядок.

getch(); return 0;

}

У процесі виконання програма відобразить на екрані таке:

Я тебе люблю

Ось як працює ця програма. Спочатку в масив strMas вводиться рядок " Я тебе люблю". Потім адреса початку цього рядка присвоюється покажчику р. Після цього кожен символ рядка strMas за допомогою функції toupper() перетвориться в його прописний еквівалент за допомогою індексування покажчика р. Пам'ятайте, що вираз р[i] за своєю дією однаковий виразу *(p+i).

6.4.3. Взаємозамінність покажчиків і масивів

Вище було показано, що покажчики і масиви дуже тісно пов'язані. І дійсно, у багатьох випадках вони взаємозамінні. Наприклад, за допомогою покажчика, який містить адресу початку масиву, можна отримати доступ до елементів цього масиву або за допомогою арифметичних дій над покажчиком, або за допомогою індексування елементів масиву. Проте в загальному випадку покажчики і масиви не є взаємозамінними. Розглянемо, наприклад, такий фрагмент коду програми:

int num[10];

int i;

for(i=0; i<10; i++) {

*num = i; // Тут все гаразд.

num++; // Помилка – змінну num модифікувати не можна.

}

Тут використовується масив цілочисельних значень з іменем num. Як зазначено в коментарі, незважаючи на те, що абсолютно прийнятно застосувати до імені num оператор "*" (який зазвичай застосовується до покажчиків), проте абсолютно неприпустимо модифікувати значення num. Йдеться про те, що num – це константа, яка вказує на початок масиву. І її, як наслідок, інкрементувати ніяк не можна. Іншими словами, хоча ім'я масиву (без індексу) дійсно генерує покажчик на початок масиву, однак його значення зміні не підлягає.

Хоча ім'я масиву генерує константу-покажчик, його, проте, (подібно до покажчиків) можна помістити у вирази, якщо, звичайно, воно при цьому не модифікується. Наприклад, наступна настанова, у процесі виконання якої елементу num[3] присвоюється значення 100, є цілком допустимою:

*(num+3) = 100; // Тут все гаразд оскільки num не змінюється.

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

Покажчики, подібно до інших типів даних, можуть зберігатися в масивах. Ось, наприклад, як виглядає оголошення 10-елементного масиву покажчиків на int-значення.

int *ipa[10];

У цьому записі кожен елемент масиву ipa містить покажчик на цілочисельне значення.

Щоб присвоїти адресу int-змінній з ім'ям var третьому елементу цього масиву покажчиків, записується таке:

ipa[2] = &var;

Необхідно пам'ятати, що тут ipa – масив покажчиків на цілочисельні значення. Елементи цього масиву можуть містити тільки значення, які є адресами змінних цілочисельного типу. Ось тому змінна var передує оператору "&".

Щоб присвоїти значення змінної var цілочисельній змінній х за допомогою масиву ipa, використовують такий синтаксис:

х = *ipa[2];

Оскільки адреса змінної var зберігається в елементі ipa[2], то застосування оператора "*" до цієї індексованої змінної дасть змогу набути значення змінній var.

Подібно до інших масивів, масиви покажчиків можна ініціалізувати. Як правило, масиви ініціалізованих покажчиків використовують для зберігання покажчиків на рядки. Наприклад, щоб створити функцію, яка виводить щасливі передбачення, можна таким чином визначити масив fortunes:

char *fortunes[] = {

"Незабаром гроші потечуть до Вас рікою.\n"

"Ваше життя осяє нове кохання.\n"

"Ви житимете довго і щасливо.\n"

"Гроші, вкладені зараз в справу, незабаром принесуть дохід.\n"

"Близький друг шукатиме Вашої підтримки.\n"

};

Не забувайте, що мова програмування C++ забезпечує зберігання всіх рядкових літералів у таблиці рядків, пов'язаній з конкретною програмою, тому масив потрібен тільки для зберігання покажчиків на ці рядки. Таким чином, для виведення другого повідомлення достатньо використовувати настанову, подібну до такої:

cout << fortunes[1];

Наведений нижче код програми передбачень є цілком коректною. Для отримання випадкових чисел у ній використовується функція rand(), а для отримання випадкових чисел в діапазоні від 0 до 4 – оператор ділення за модулем, оскільки саме такі числа можуть слугувати для доступу до елементів масиву за індексом.

Код програми 6.8. Демонстрація механізму використання масиву покажчиків

#include <vcl>

#include <iostream> // Для потокового введення-виведення

#include <cstdlib> // Для використання бібліотечних функцій

#include <conio.h> // Для консольного режиму роботи

using namespace std; // Використання стандартного простору імен

char *fortunes[] = {

"Незабаром гроші потечуть до Вас рікою.\n"

"Ваше життя осяє нове кохання.\n"

"Ви житимете довго і щасливо.\n"

"Гроші, вкладені зараз в справу, незабаром принесуть дохід.\n"

"Близький друг шукатиме Вашої підтримки.\n"

};

int main()

{

int chance;

cout << "Щоб дізнатися про свою долю, натисніть будь-яку клавішу: ";

// Рандомізуємо генератор випадкових чисел.

while(!kbhit()) rand();

cout << "\n";

chance = rand();

chance = chance % 5;

cout << fortunes[chance];

getch(); return 0;

}

Звернемо Вашу увагу на цикл while, який викликає функцію rand() доти, доки не буде натиснуто на яку-небудь клавішу. Оскільки функція rand() завжди генерує одну і ту саму послідовність випадкових чисел, важливо мати можливість програмно використовувати цю послідовність з певної довільної позиції1. Ефект випадковості досягається за рахунок повторних звернень до функції rand(). Коли користувач натисне на клавішу, цикл зупиниться на деякій випадковій позиції послідовності чисел, що генеруються, і ця позиція визначить номер повідомлення, яке буде виведено на екран. Нагадаємо, що функція kbhit() є достатньо поширеним розширенням бібліотеки функцій мови програмування C++, що забезпечується багатьма компіляторами, але не входить в стандартний пакет бібліотечних функцій мови C++.

У наведеному нижче прикладі використовується двовимірний масив покажчиків для розроблення програми, яка відображає синтаксис-пам'ятку за ключовими словами мови програмування C++. У програмі ініціалізується перелік покажчиків на рядки. Перша розмірність масиву призначена для вказівки на ключові слова мови програмування C++, а друга – на короткий їх опис. Перелік завершується двома нульовими рядками, які використовуються як ознака кінця списку. Користувач вводить ключове слово, а програма повинна вивести на екран його опис. Як бачимо, цей перелік містить всього декілька ключових слів. Тому його продовження залишається за Вами.

Код програми 6.9. Демонстрація відображення синтаксис-пам'ятки за ключовими словами мови програмування C++

#include <iostream> // Для потокового введення-виведення

#include <cstring> // Для роботи з рядковими типами даних

using namespace std; // Використання стандартного простору імен

char *keyword[][2] = {

"for", "for(ініціалізація; умова; інкремент)",

"if", "if(умова)... else ...",

"switch", "switch(значення) { case-перелік }",

"while", "while(умова)...",

// Сюди потрібно додати решту ключових слів мови програмування C++.

"", "" // Перелік повинен завершуватися нульовими рядками.

};

int main()

{

char strMas[80];

int i;

cout << "Введіть ключове слово: ";

cin >> strMas;

// Відображаємо синтаксис.

for(i=0; *keyword[i][0]; i++)

if(!strcmp(keyword[i][0], strMas)) cout << keyword[i][1];

getch(); return 0;

}

Ось приклад виконання цієї програми:

Введіть ключове слово: for

for(ініціалізація; умова; інкремент)

У цій програмі зверніть увагу на керівний вираз циклом for. Він призводить до завершення циклу, коли елемент keyword[i][0] містить покажчик на нуль, який інтерпретується як значення ФАЛЬШ. Отже, цикл зупиняється тоді, коли трапляється нульовий рядок, який завершує масив покажчиків.