Урок №97. Вказівники на вказівники

  Юрій  | 

  Оновл. 26 Сер 2021  | 

 192

Вказівник на вказівник — це саме те, про що ви подумали: вказівник, який містить адресу іншого вказівника.

Вказівники на вказівники

Звичайний вказівник типу int оголошується з використанням однієї зірочки:

Вказівник на вказівник типу int оголошується з використанням двох зірочок:

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

Результат виконання програми:

7
7

Зверніть увагу, ви не можете ініціалізувати вказівник на вказівник безпосередньо значенням:

Це пов’язано з тим, що оператор адреси (&) вимагає l-value, але &value — це r-value. Однак, вказівнику на вказівник можна вказати значення nullptr:

Масиви вказівників

Вказівники на вказівники мають кілька застосувань. Найбільш використовуваним є динамічне виділення масиву вказівників:

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

Двовимірні динамічно виділені масиви

Іншим поширеним застосуванням вказівників на вказівники є динамічне виділення багатовимірних масивів. На відміну від двовимірного фіксованого масиву, який можна легко оголосити наступним чином:

Динамічне виділення двовимірного масиву трохи відрізняється. У вас може виникнути спокуса написати щось на кшталт такого:

Тут ви отримаєте помилку. Є два можливих рішення. Якщо правий індекс є константою типу compile-time, то ви можете зробити наступне:

Дужки тут потрібні для дотримання пріоритету. У C++11 хорошою ідеєю буде використовувати ключове слово auto для автоматичного визначення типу даних:

На жаль, це відносно просте рішення не працює, якщо правий індекс не є константою типу compile-time. В такому випадку все трохи ускладнюється. Спочатку ми виділяємо масив вказівників (як у вищенаведеному прикладі), а потім перебираємо кожен елемент масиву вказівників і виділяємо динамічний масив для кожного елементу цього масиву. В підсумку, наш динамічний двовимірний масив — це динамічний одновимірний масив динамічних одновимірних масивів!

Доступ до елементів масиву виконується як зазвичай:

Цим методом, оскільки кожен стовпець масиву незалежно динамічно виділяється, можна зробити динамічно виділені двовимірні масиви, які не є прямокутними. Наприклад, ми можемо створити масив трикутної форми:

У вищенаведеному прикладі, array[0] — це масив довжиною 1, а array[1] — масив довжиною 2 і т.д.

Для звільнення пам’яті динамічно виділеного двовимірного масиву (який створювався за допомогою цього способу) також потрібен буде цикл:

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

Оскільки процес виділення і звільнення двовимірних масивів є трохи заплутаним (можна легко наробити помилок), то часто простіше «сплюснути» двовимірний масив в одновимірний масив:

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

Вказівник на вказівник на вказівник і т.д.

Також можна оголосити вказівник на вказівник на вказівник:

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

Або зробити ще більшу вкладеність, якщо захочете. Однак на практиці такі вказівники рідко коли використовуються.

Висновки

Рекомендується застосовувати вказівники на вказівники тільки в крайніх випадках, так як вони складні у використанні і потенційно небезпечні. Досить легко розіменувати нульовий або висячий вказівник в ситуаціях з використанням звичайних вказівників, вдвічі легше це зробити в ситуаціях з вказівником на вказівник, оскільки для отримання початкового значення потрібно виконати подвійне розіменування!

Оцінити статтю:

1 Зірка2 Зірки3 Зірки4 Зірки5 Зірок (4 оцінок, середня: 5,00 з 5)
Loading...

Залишити відповідь

Ваш E-mail не буде опублікований. Обов'язкові поля відмічені *