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

Лекція 28-29. Програмування на мові С++. Вказівники

Вказівники є надзвичайно істотною і характерною особливістю С++. От найчастіші приклади їх використання:

  • доступ до елементів масиву

  • передача аргументів в функцію, від якої вимагається змінити ці аргументи

  • передача в функцію масивів та рядкових змінних

  • виділення пам’яті

  • створення складних структур таких як зв’язний список.

Адреси і вказівники

Ідея вказівників нескладна. Почнемо з того, що кожен байт пам’яті компютера має адресу. Заванатжуючись в пам’ять, наша програма займає якусь кількість цих адрес. Це означає, що кожна змінна і кожна функція нашої програми починається з конкретної адреси.

Операція одержання адреси &

Ми можемо одержати адресу змінної, використовуючи операцію одержання адреси &. Розглянемо невеличку програму, що показує, як це робити:

#include <iostream>

using namespace std;

int main()

{int var=11;

int var2=22;

int var3=33;

cout<<&var1<<endl

<<&var2<<endl

<<&var3<<endl;

return 0;

}

В цій програмі визначено 3 цілочисельні змінні, які ініціалізовані значеннями 11, 22 і 33. Ми виводимо на екран адреси цих змінних.

Реальні адреси, зайняті змінними в програмі, залежать від багатьох факторів таких як компютер, на якому запущена програма, розмір оперативної пам’яті, наявність іншої програми в пам’яті. Тому при різних запусках цієї програми ми, найшвидше, одержимо різні результати.

Використання операції << дозволяє показати адреси в 16-ій системі. Адреси розміщені в спадаючому порядку, оскільки локальні змінні зберігаються в стеку, де їх адреси розміщені за спаданням. Якщо ж використовуються глобальні змінні, то їх адреси розміщуються в порядку зростання, оскільки глобальні змінні зберігаються в купі.

Змінні вказівники

Адресний простір обмежений. Можливість довідатися, де розміщена певна змінна, корисна, але бачити саме значення адреси потрібно рідко. Потенційне збільшення наших можливостей в програмуванні вимагає реалізації такої ідеї: нам необхідні змінні, що зберігають значення адреси. Нам знайомі змінні, що зберігають знаки, числа з плаваючою крапкою, цілі та інші. Адреси зберігаються так само. Змінна, що містить значення адреси, називається змінною-вказівником або просто вказівником.

Змінна-вказівник не належить до того ж типу, що й змінна, адресу якої вона зберігає: вказівник на int не має типу int. Так само, в С++ не існує типу pointer. Все виглядає дещо складніше, як показано в наступній програмі:

#include<iostream>

using namespace std;

int main()

{ int var1=11;

int var2=22;

cout<<&var1<<endl

<<&var2<<endl;

int* ptr; //вказівник на ціле число

ptr=&var1;

cout<<ptr<<endl;

ptr=&var2;

cout<<ptr<<endl;

return 0;

}

В рядку

int* ptr; //вказівник на ціле число

визначена змінна-вказівник. Зірочка означає вказівник на. Тобто, змінна визначена як вказівник на int, тобто ця змінна може містити в собі адресу змінної цілого типу.

Синтаксис С++ дає змогу визначати вказівники наступним чином:

char* cptr; //вказівник на символьну змінну

int* iptr; //вказівник на ціле

float* fptr; //вказівник на дійсний тип

Недоліки синтаксису

Треба зауважити, що загальноприйняте визначення вказівника за допомогою змінної, що пишеться перед іменем змінної, а не після назви типу

char *charptr;

Це не принципово для компілятора, але зірочка, розміщена відразу після назви типу змінної, сигналізує про те, що це не просто тип, а вказівник на нього.

Якщо ми визначаємо в одному рядку більше, ніж один вказівник того самого типу, то зірочку необхідно ставити перед іменем кожної змінної.

char* ptr1, * ptr2, * ptr3;

І в цьому випадку можна використати стиль написання, при якому зірочка ставиться поруч з іменем.

char *ptr1, *ptr2, *ptr3;

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