На цьому уроці ми розглянемо вказівники на константні змінні, вказівники на константні значення, константні вказівники і константні вказівники на константні значення в мові C++.
Вказівники на константні змінні
До цього моменту всі вказівники, які ми розглядали, були неконстантними вказівниками на неконстантні значення:
1 2 3 |
int value = 7; int *ptr = &value; *ptr = 8; // змінюємо значення value на 8 |
Однак, що станеться, якщо вказівник буде вказувати на константну змінну?
1 2 3 |
const int value = 7; // value - це константа int *ptr = &value; // помилка компіляції: неможливо конвертувати const int* в int* *ptr = 8; // змінюємо значення value на 8 |
Вищенаведений фрагмент коду не скомпілюється: ми не можемо присвоїти неконстантному вказівнику константну змінну. В цьому є сенс, адже на те вона і константа, що її значення не можна змінити. Гіпотетично, якби ми могли присвоїти константне значення неконстантному вказівнику, то тоді ми могли б розіменувати неконстантний вказівник і змінити значення цієї ж константи. А це вже є порушенням самого поняття «константа».
Вказівники на константні значення
Вказівник на константне значення — це неконстантний вказівник, який вказує на константу. Для оголошення вказівника на константне значення, використовується ключове слово const перед типом даних:
1 2 3 |
const int value = 7; const int *ptr = &value; // тут все ок: ptr - це неконстантний вказівник, який вказує на "const int" *ptr = 8; // заборонено, ми не можемо змінити константне значення |
У прикладі, наведеному вище, ptr
вказує на константний цілочисельний тип даних.
Поки що все добре. Розглянемо наступний приклад:
1 2 |
int value = 7; // value - це не константа const int *ptr = &value; // все добре |
Вказівник на константну змінну може вказувати і на неконстантну змінну (як у випадку зі змінною value
у вищенаведеному прикладі). Подумайте про це так: вказівник на константну змінну оброблює змінну як константу при отриманні доступу до неї незалежно від того, чи була ця змінна від самого початку визначена як const чи ні. Таким чином, наступне в порядку речей:
1 2 3 |
int value = 7; const int *ptr = &value; // ptr вказує на "const int" value = 8; // змінна value уже не константа, якщо до неї отримують доступ через неконстантний ідентифікатор |
Але не наступне:
1 2 3 |
int value = 7; const int *ptr = &value; // ptr вказує на "const int" *ptr = 8; // ptr оброблює value як константу, тому зміна значення змінної value через ptr не допускається |
Вказівнику на константне значення, який при цьому сам не є константним (він просто вказує на константне значення), можна присвоїти і інше значення:
1 2 3 4 5 |
int value1 = 7; const int *ptr = &value1; // ptr вказує на const int int value2 = 8; ptr = &value2; // добре, ptr тепер вказує на інший const int |
Константні вказівники
Ми також можемо зробити вказівник константним. Константний вказівник — це вказівник, значення якого не може бути змінено після ініціалізації. Для оголошення константного вказівника використовується ключове слово const між зірочкою і ім’ям вказівника:
1 2 |
int value = 7; int *const ptr = &value; |
Подібно звичайним константним змінним, константний вказівник повинен бути ініціалізований при оголошенні. Це означає, що він завжди буде вказувати на одну і ту же адресу. У вищенаведеному прикладі ptr
завжди буде вказувати на адресу value
(до тих пір, поки вказівник не вийде з області видимості і не знищиться):
1 2 3 4 5 |
int value1 = 7; int value2 = 8; int * const ptr = &value1; // ок: константний вказівник ініціалізований адресою value1 ptr = &value2; // не ок: після ініціалізації константний вказівник не може бути змінений |
Однак, оскільки змінна value
, на яку вказує вказівник, не є константою, то її значення можна змінити шляхом розіменування константного вказівника:
1 2 3 |
int value = 7; int *const ptr = &value; // ptr завжди буде вказувати на value *ptr = 8; // ок, так як ptr вказує на тип даних (неконстантний int) |
Константні вказівники на константні значення
Нарешті, можна оголосити константний вказівник на константне значення, використовуючи ключове слово const як перед типом даних, так і перед ім’ям вказівника:
1 2 |
int value = 7; const int *const ptr = &value; |
Константний вказівник на константне значення не можна перенаправити вказувати на інше значення так же, як і значення, на яке він вказує, — не можна змінити.
Висновки
Підводячи підсумки, вам потрібно запам’ятати всього лише 4 правила:
Неконстантний вказівник можна перенаправити вказувати на будь-яку іншу адресу.
За допомогою вказівника на неконстантне значення можна змінити це ж значення (на яке він вказує).
Константний вказівник завжди вказує на одну і ту ж адресу, і ця адреса не може бути змінена.
Вказівник на константне значення обробляє значення як константне (навіть якщо воно таким не є) і, відповідно, це значення через вказівник змінити не можна.
А ось з синтаксисом може бути трохи важче. Просто пам’ятайте, що тип значення, на який вказує вказівник, завжди знаходиться зліва (на самому початку):
1 2 3 4 |
int value = 7; const int *ptr1 = &value; // ptr1 вказує на "const int", тому це вказівник на константне значення int *const ptr2 = &value; // ptr2 вказує на "int", тому це константний вказівник на неконстантне значення const int *const ptr3 = &value; // ptr3 вказує на "const int", тому це константний вказівник на константне значення |
Вказівники на константні значення в основному використовуються в параметрах функцій (наприклад, при передачі масиву) для гарантії того, що функція випадково не змінить значення переданого їй аргументу.