Урок №105. Передача по адресі

  Юрій  | 

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

 223

Є ще один спосіб передачі змінних у функцію в мові C++ — по адресі.

Передача по адресі

Передача аргументів по адресі — це передача адреси змінної-аргументу (а не вихідної змінної). Оскільки аргумент є адресою, то параметром функції повинен бути вказівник. Потім функція зможе розіменувати цей вказівник для доступу або зміни вихідного значення. Ось приклад функції, яка приймає параметр, який передається по адресі:

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

value = 4
value = 7

Як ви можете бачити, функція boo() змінила значення аргументу (змінну value) через параметр-вказівник ptr. Передачу по адресі зазвичай використовують з вказівниками на звичайні масиви. Наприклад, наступна функція виведе всі значення масиву:

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

Результат:

9 8 6 4 3 2 1

Пам’ятайте, що фіксовані масиви конвертуються у вказівники при передачі у функцію, тому їх довжину потрібно передавати в якості окремого параметру. Перед розіменуванням параметрів, переданих по адресі, не зайвим буде перевірити — чи не є вони нульовими вказівниками. Розіменування нульового вказівника призведе до збою в програмі. Ось функція printArray() з перевіркою (виявленням) нульових вказівників:

Передача по константній адресі

Оскільки printArray() все одно не змінює значення отриманих аргументів, то гарною ідеєю буде зробити параметр array константою:

Так ми бачимо відразу, що printArray() не змінить переданий аргумент array. Коли ви передаєте вказівник у функцію по адресі, то значення цього вказівника (адреса, на яку він вказує) копіюється з аргументу в параметр функції. Іншими словами, він передається по значенню! Якщо змінити значення параметру функції, то зміниться тільки копія, вихідний вказівник-аргумент не буде змінено. Наприклад:

У tempPtr копіюється адреса вказівника ptr. Незважаючи на те, що ми змінили tempPtr на нульовий вказівник (присвоїли йому nullptr), це ніяк не вплинуло на значення, на яке вказує ptr. Отже, результат виконання програми:

6
6

Зверніть увагу, хоча сама адреса передається по значенню, ви все одно можете розіменувати її для зміни значення вихідного аргументу. Заплутано? Давайте розберемося детально:

   При передачі аргументу по адресі в змінну-параметр функції копіюється адреса з аргументу. У цей момент параметр функції і аргумент вказують на одне і те ж значення.

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

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

У наступній програмі це все добре проілюстровано:

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

6
7

Передача адрес по посиланню

Виникає питання: «А що, якщо ми хочемо змінити адресу, на яку вказує аргумент, всередині функції?». Виявляється, це можна зробити дуже легко. Ви можете просто передати адресу по посиланню. Синтаксис посилання на вказівник може здатися трохи дивним, але все ж:

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

6 ptr is null

Нарешті, наша функція setToNull() дійсно змінила значення ptr з &six на nullptr!

Існує тільки передача по значенню

Тепер, коли ви розумієте основні відмінності між передачею по посиланню, по адресі і по значенню, давайте трохи поговоримо про те, що знаходиться “під капотом”.

На уроці про посилання ми згадували, що посилання насправді реалізуються за допомогою вказівників. Це означає, що передача по посиланню є просто передачею по адресі. І трохи вище ми говорили, що передача по адресі насправді є передачею адреси по значенню! З цього випливає, що мова C++ дійсно передає все по значенню!

Плюси і мінуси передачі по адресі

Плюси передачі по адресі:

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

   Оскільки копіювання аргументів не відбувається, то швидкість передачі по адресі досить висока, навіть якщо передавати великі структури або класи.

   Ми можемо повернути відразу декілька значень з функції, використовуючи параметри виводу.

Мінуси передачі по адресі:

   Всі вказівники потрібно перевіряти, чи не є вони нульовими. Спроба розіменувати нульовий вказівник призведе до збою в програмі.

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

Коли використовувати передачу по адресі:

   при передачі звичайних масивів (якщо немає ніяких проблем з тим, що масиви конвертуються у вказівники при передачі).

Коли не використовувати передачу по адресі:

   при передачі структур або класів (використовуйте передачу по посиланню);

   при передачі фундаментальних типів даних (використовуйте передачу по значенню).

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

Правило: Використовуйте передачу по посиланню, замість передачі по адресі, коли це можливо.

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

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

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

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