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

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

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

6.1. Вказівники і адреси

Вказівник містить адресу об’єкта, що дає змогу «непрямого» доступу до цього об’єкта через вказівник. Якщо х – змінна типу int, рх – вказівник, а унарна операція & видає адресу об’єкта, то оператор рх = ; присвоює адресу х змінній рх, тобто рх «вказує» на х. Операцію & застосовують тільки до змінних і елементів масиву, її також не можна застосовувати до регістрової змінної.

Унарна операція * розглядає свій операнд як адресу змінної і звертається за цією адресою, щоб одержати значення змінної. Отже, якщо змінна y типу int, то y = *рх; присвоює y значення того, на що вказує рх. Тому послідовність:

рх = &х;

y = *рх;

присвоює y те ж саме значення, що й оператор y = x;

Змінні потрібно описати:

int x, y; // опис x і y

int *px; // опис вказівника

Мнемонічний опис вказівника int *px; свідчить про те, що комбінація *px має тип int. Це означає, що якщо px з’являється в контексті *px, то це еквівалентно змінній типу int. Фактично синтаксис опису змінної імітує синтаксис виразів, у яких ця змінна може з’являтися. Наприклад, double Atof(), *dp; показує, що Atof() і *dp мають у виразах значення типу double. Зауважимо, що вказівник може вказувати тільки на певний вид об’єктів. Вказівники можуть входити у вираз. Наприклад, якщо px вказує на ціле x, то *px може з’являтися в будь-якому контексті, де може трапитися x. Так, оператор y = *px + 1 присвоює y значення на одиницю більше відзначення x; printf("%d\n", *px) – друкує поточне значення x; d = sqrt((double) *px) – отримує в d квадратний корінь із x, причому до передачі функції sqrt значення x перетворюється до типу double.

У виразах вигляду у = *px + 1 унарні операції * і & зв’язані зі своїм операндом, тому такий вираз бере те значення, на яке вказує px, додає одиницю і присвоює результат змінній y.

Посилання на вказівники можуть з’являтися і в лівій частині присвоєнь. Якщо px вказує на x, то *px = 0 встановлює x = 0, а *px += 1 збільшує його на одиницю, як і вираз (*px)++. Круглі дужки в (*px)++ необхідні. Якщо їх випустити (унарні операції типу *і++ виконуються справа наліво), то буде збільшено px, а не змінну, на яку він вказує.

Оскільки вказівники є змінними, то їх можна використовувати як звичайні змінні. Якщо py – інший вказівник на змінну типу int, то py = px копіює вміст px у py, в результаті чого py вказує на те ж, що й px.

6.2. Вказівники і аргументи функцій

У мові C++ передача аргументів функціям здійснюється «за значенням», тому викликана процедура не може безпосередньо змінити змінну із викличної програми. Наприклад, у програмі сортування (див. ПП6.1 на СD) потрібно поміняти два елементи за допомогою функції Swap. Для цього недостатньо написати Swap (a, b), через виклик за значенням swap не може впливати на аргументи a і b у викличній функції. Бажаний ефект можна одержати так. Виклична програма передає вказівники, які підлягають зміні значень: Swap(&a, &b); операція & видає адресу змінної, тому &a є вказівником на a. У swap аргументи описуються як вказівники і доступ до фактичних операндів здійснюється через них (див. ПП6.2 на СD).

Вказівники як аргументи використовуються у функціях, які повинні повертати більше одного значення. Наприклад, функція swap повертає два значення і нові значення її аргументів. Як приклад розглянемо функцію GetInt, що здійснює перетворення даних, які надходять у вільному форматі, розділяючи потік символів на цілі значення (по одному цілому за один цикл). Функція GetInt має повертати або знайдене значення, або ознаку EOF, якщо вхідні дані вичерпані. Ці значення повинні повертатися як окремі об’єкти, яке б значення не означало EOF.

У разі виходу на EOF GetInt повертає EOF як значення функції, а будь-яке інше повернуте значення – це нормальне ціле. Числове ж значення знайденого цілого повертається через аргумент, що має бути вказівником цілого. Такий підхід розділяє статус EOF і числові значення.

Наступний цикл заповнює масив цілими за допомогою звертань до функції GetInt:

int n, v, array[size];

for (n=0; n<size && GetInt(&v)!= eof; n++)

array[n]= v;

У результаті кожного обходу v стає рівним наступному цілому значенню, знайденому у вхідних даних. Як аргумент GetInt потрібно вказати &v, а не v. Використання просто v призведе до помилки адресації, оскільки GetInt працює з вказівником (див. ПП6.3 на СD).

Вираз *pn використовується в GetInt як звичайна змінна типу int. Задіяні функції GetCh та UngetCh, так, що один зайвий символ, який доводиться читати, може бути розміщений знову в потоці введення.