Всім привіт! Ми продовжуємо з вами курс по основам програмування на C++ і сьогоднішня наша тема це вказівники. Вказівники це окремий тип даних, або можна сказати окрема змінна, яка зберігає унікальні якісь дані, унікальну інформацію. Інформація являється адресою. Адреса комірки пам'яті.
Якщо ми з вами пригадаємо, що ми працюємо з змінними, а змінні це в нас відповідно якась комірка пам'яті, то кожна комірка має певні характеристики. Ми даємо її ім'я, визначаємо тип нашої комірки, і відповідно комірка також має свою адресу в оперативній пам'яті. В деяких випадках нам потрібно взяти цю адресу, покласти в якесь інше середовище, в якусь іншу комірку, для того, щоб мати непрямий доступ через цю комірку до комірки, в яку ми взяли адресу.
Такі комірки. Називається вказівниками, тобто змінна, яка може в собі зберігати адресу іншої змінної. Для чого вона потрібна?
Для того, щоб мати непрямий доступ, наприклад, коли ми передаємо інформацію у функцію. Або, наприклад, для отримання динамічної пам'яті. Коли ми з вами розпочнемо вивчення динамічної пам'яті, ви побачите, що ми з вами отримаємо не тільки об'єм певної пам'яті, а отримаємо також адресу для того, щоб взаємодіяти з цією пам'яттю. І тому нам треба цю адресу зберігати.
Ми будемо класти її, відповідно, в нашу змінну. І така зміна є ще раз вказівником. Називається скорочено PTR і недаремно я прописав зірочка. Ми вже по передніх наших лекціях з вами зустрічали вказівник. Коли використовували, наприклад, фолинці для пошуку максимального або мінімального елемента.
Або, можливо, для пошуку якогось іншого значення. Вказівники ми вже використовували, а сьогодні детальніше з ними попрацюємо. І так, вказівник це змінна, так? Вона повинна зберігати адресу іншої зміни.
Тому для початку ми створимо з вами адресу, точніше створимо змінну. Змінну, наприклад, типу int, присвоємо її значення 10. Якщо змінна має адресу, тепер ми цю адресу можемо взяти і кудись покласти. Для цього ми створимо вказівник. І якщо вказівник буде вказувати на змінну типу int, то відповідно такий вказівник ми повинні також створити використовуючи тип int. Пишемо int, використовуємо зірочка ptr.
Зірочка це як уже сигнал того, що це не звичайна змінна, а вказівник. Тобто ми створюємо вказівник. Можемо поставити відразу крапка з комою.
На даному етапі ми вже створили вказівник. Це зміна, яка може сперегати адресу іншої змінної. Що далі? Тепер нам потрібно якось взяти адресу нашої змінної x і покласти її в ptr.
Яким чином це можна зробити? Ми пишемо ptr, відкриво. Пишемо операцію присвоювання і ми повинні присвоїти адресу.
Для того, щоб взяти адресу нашої змінної Х, потрібно використовувати символ Ampersand. Ampersand надає нам можливість отримати адресу змінної будь-якого типу, або, наприклад, адреси вказівника, або адреси масиву. Вставимо Х і беремо відповідну адресу нашої змінної Х. ПТР равно Х. Тобто тепер PTR зберігається адреса.
Якщо, наприклад, ми на даному етапі попробуємо вивести інформацію, яка зберігається в нашому PTR, std.endl через c.au на консоль, скомпілюємо нашу роботу, очікуємо, поки компілюється, запускаємо, то ми виводимо набір символів. Це і є адреса нашої зміни. Як впевнитися, що це вона і є?
Ми можемо так само застосувати Виведення нашої змінної X, але не просто значення, яке в ній зберігається, а використати до неї амперсант, який повертає адресу. І відповідно потім знову цю адресу вивести на консоль. Компілюємо.
Як бачимо, ми виводимо однакові значення на одному рядку адресу, на іншому рядку також саму адресу. Відповідно, ми вірно поклали адресу змінної X нашу PTR. Підсумуємо, що ми з вами можемо отримати адресу, використовуючи амперсант, і тепер можемо вкласти її в PTR.
Що це нам дає? Як я наголошував, що ми тепер маємо непрямий доступ через наш вказівник до змінної, відповідно, на яку ми вказуємо. Ми можемо тепер якимось чином взаємодіяти з цією змінною, так як вказівник не вказуєш. Яким чином ми будемо взаємодіяти? Ми можемо змінити значення, написати 5R равно 10. Але це буде не так вірно, тому що просто прописавши 5R равно 10 буде некоректно.
Операція присвоювання це прямий доступ до всередині нашої зміни. Тобто ми хочемо присвоїти, покласти якусь інформацію всередину нашої зміни. Але ми знаємо, що ми можемо туди покласти тільки вказівник, а не чесно. Але я хочу тут реалізувати доступ до змінної Х. Яким чином я можу це зробити?
Для того, щоб отримати доступ до моєї змінної Х, на яку вказує PTR, мені потрібно написати зірочка. Зірочка PTR рівне 10. Що це значить? Я таким чином отримую доступ до змінної х, на яку вказує мій вказівник.
І тепер напряму в неї взаємодіюю через вказівник. Тобто, якщо я пишу зірочка 5р рівне, наприклад, 20, то я цю 20 кладу в змінну, на яку вказує мій вказівник. Якщо я пишу, наприклад, 5р равно ампересант х, то я беру адресу і кладу її в вказівник. Тобто, якщо без зірки використовуємо, то ми взаємодіємо з самою змінною вказівник і кладемо якусь в неї всередину інформацію. І там тільки може бути один тип інформації це адреса.
Але якщо ми використовуємо зірку перед назвою нашого вказівника, то, відповідно, ми хочемо взаємодіяти з зміною, на яку ми вказуємо. І таку операцію використовувати потрібно тільки в тому випадку, якщо ми на щось дійсно вказуємо. Тому що якщо ми нічого вказувати не будемо, буде помилка виникати на етапі компіляції, тому що ми нічого не вказуємо і операцію розмінування робити не можна. І така дія називається операція розмінування.
Що ми можемо зараз перевірити, чи дійсно ми отримали доступ до нашої зміни. Давайте покладемо якесь інше значення 15 і потім повторно виведемо нашу змінну x. cout, вводимо x. std endl.scom.
Компілюємо повторно. Запускаємо. Виводимо попередні адреси і виводимо, відповідно, 15. Ми виводили на рядку №17 змінну X.
І як бачите, ми тут що знайшли? Точніше, що ми отримали? Ми отримали 15, яке ми поклали через вказівник.
Може бути існувати і вказівник на вказівник. Тобто, так само як вказівник є коміркою пам'яті, то, відповідно, і в нього є адреса. Тобто, ми можемо створювати вказівник на вказівник. вказівник на вказівник на вказівник і так далі. Більш детальніше про вказівник на вказівник ми розберемо, коли будемо вивчати з вами роботу з динамічною пам'яттю і коли будемо створювати двохвимірні динамічні масиви.
Там ви більш детальніше зрозумієте принцип вказівника на вказівника. Поки що нам достатньо зрозуміти, що вказівник це в нас з вами змінна, яка може зберігати адреси. Відповідно, для того, щоб покласти адресу змінної, Ми використовуємо амперсант, як показано на рядку №10. Для того, щоб створити вказівник, ми використовуємо тип нашого вказівника. Ми вказуємо той тип, на який ми будемо вказувати.
Потім використовуємо зірку, ми говоримо, що це буде вказівник. Для того, щоб знову через вказівник якесь покласти значення на те, що ми вказуємо, ми використовуємо знову зірку 5R равно 15. Таким чином змінюємо значення, на яке ми вказуємо. Самі прості способи взаємодії з вказівником.
Те, що я тільки що для вас показав. Давайте попробуємо виконати декілька практичних робіт і більш детальніше зрозуміємо, як ми можемо використовувати наш вказівник. Розпочнемо з першого завдання.
Робота з масивами чисел. Створіть масив цілих чисел та визначіть його розмір. Написати функцію, яка приймає масив і його розмір в якості параметрів і та виводить ці елементи масиву на консоль за допомогою вказівника.
Ми будемо передавати в функцію наш масив, але функція буде на спараметри. Пам'ятаємо, параметри це те, що знаходиться в круглодужках. Це в нас буде int і вказівник. Тобто ми будемо передавати адресу нашого масиву вказівнику.
І потім будемо використовувати певні дії з нашим вказівником. Закоментуємо попередній приклад застосування вказівника. Пишемо int main. Відкриваємо фігурні дужки. Створюємо масив цілочасального типу.
Відразу його давайте ініціалізуємо. Пропишемо 1, 2, 3, 4, 5. Достатньо на 5 елементів. Потрібно отримати розмір. Пригадуємо, що розмір ми можемо отримати двома способами. Це або використовуючи функцію size в бібліотеки алгоритм, або використовувати sizeof, який повертає загальний об'єм.
Два способи можна реалізовувати, але використовуючи sizeof, тут потрібно пригадати, що там додатково відбувається арифметична якась дія. Ми повинні поділити загальний об'єм на... Об'єм нашої однієї змінної, то ми отримаємо такий розмір.
Давайте пригадаємо, як використовувати сайзову. Користовуватимемося SIZOV, пишемо RRA, отримаємо загальний об'єм, поділити на SIZOV, круглі дужки, RRA, квадратні дужки, 0. Далі ми створимо функцію, яка буде виводити наш масив, функція нічого не повертає, буде типово відпишемо, що функція називається у нас SPRINT, відкриваємо круглі дужки, функція у нас приймає масив. Але приймати буде не звичайний, як ми зазвичай пишемо, для того, щоб передати наш масив, а в нас буде в якості... прийняття масиву вказівник на наш масив пишемо інт зірочка пітер і інт сайз передаємо також розмір а всередині інт мейн викликаємо нашу функцію принт відкриваємо кролі дужки і повинні передати вказівник Точніше повинні передати адресу пишу арарей крапка з комою сайз Як бачите, ми тут не використовуємо амперсант.
Чому не використовуємо амперсант? Тому що назва нашого масиву і є, по факту, вказівник на перший елемент нашого масиву. Якби ми передавали адресу зміною, то, наприклад, потрібно було нам прописати амперсант.
В наступному прикладі я вам це продемонструю. Давайте дореалізуємо нашу функцію. Вона приймає в нас вказівник на наш масив і розмір. Функція повинна вивести...
наш масив. Виводити будемо через цикл for, пишемо int i ровно 0 i менше size i плюс плюс відкриваємо фігурні дужки і тепер нам потрібно вивести наш з вами масив яким чином ми будемо виводити наш масив через вказівник тут буде супер легка реалізація вона пов'язана з тим, що так як вказівник має можливість використовувати індексацію Ми можемо назву нашого вказівника використовувати як назву нашого масиву, тобто подібне до того, як ми працювали з звичайним масивом. Використовуємо квадратні дужки, вказуємо порядковий номер елемента і відповідно звертаємося до якогось елемента. Так само можна це вже використовувати з вказівником.
Пишемо ptri відступ, крапка з комою. І потім перехід на номер ряду std, endl, крапка з комою. Точніше не endl, а cout. cout std endl.com Компілюємо нашу роботу.
Використовуємо стандарт компілювання, тому що ми робимо ініціалізацію, яка тільки доступна в нас після 11-го року стандарту C++. Зкомпілювати з новим стандартом. Запускаємо.
Виводимо наш масив 1, 2, 3, 4, 5. От така проста реалізація. Цього разу ми використовували вказівник. Наголошую ще раз, що з вказівником можна використовувати індексацію, якщо це масив. Як це працює?
Це працює те, що, відповідно, вказівник отримує адресу першого елемента, і ми потім можемо виконувати з вказівником якісь певні арифметичні дії. Яким чином це відбувається? Просто ми робимо індекс.
вказуємо на передковий номер, який йде після того елемента, на який ми вказуємо. Закоментуємо цей приклад і тепер вам покажу ще один приклад застосування. Минулого разу я показував, що можна використовувати ссылки в якості функції swap, коли ми передаємо функцію певні елементи для того, щоб зробити swap.
Цього разу ми застосуємо вказівник. Пишемо int main, створимо ми дві змінні. Буде у нас і змінна int рівно, наприклад, 20, змінна int y рівно 30, з комою. Виводимо std cout, змінна x, двокрапка, змінна x.
Потім виводимо також y змінну, пробіл y, двокрапка, і виводимо відповідно y. std angle.sql. Реалізовуємо функцію.
Функція в нас нічого повертати також не буде, буде називатися в нас swap. Закриваємо круглі дужки. І в якості передачі аргументів в нас будуть тут вказівники.
Буде int зірочка x і int зірочка y. В фігурні дужки пригадуємо, що swap робиться за допомогою додаткової змінної. Пишемо int зірочка або просто tm.
Пі. Равно, для того, щоб отримати значення, на яке вказує вказівник, ми повинні використовувати відповідну операцію розмінування. Пишемо зірочка Х, потім ми пишемо з вами зірочка Х равно зірочка У, і далі пишемо зірочка У равно ГМП.
Крапка з коми. Якщо ми хочемо взаємодіяти з тим, на що вказує вказівник, то ми повинні робити операцію розмінування. Це тому, що ми ж будемо передавати у функцію не копії, не посилання, а будемо передавати адреси наших змінних x та y.
Коли я викликаю тепер swap функцію свою, відкриваю круглі дужки, я буду передавати адреси змінної x та y. Для того, щоб мені отримати адреси, пригадуємо, ми використовуємо амперсан. Прописуємо амперсан, ставимо x, прописуємо амперсан, ставимо y.
Крапка з комою. Копіюємо ще раз рядок при виведенні змінної x та y. Ставимо після виклику нашої функції swap.
І попробуємо зараз скомпілювати нашу роботу. Компілюємо. Запускаємо.
X20, Y30, X30, Y20. Цього разу у нас відбулося з вами відповідно замінення значень між X та Y. Пригадаю, якщо ми не будемо використовувати казівники, давайте поприбираємо кругом ці ручки. І також попробуємо амперсанти.
Якщо ми будемо просто передавати по замовчуванню наші змінні, то ми будемо передавати копію інформації, тієї інформації, яка зберігається в X та Y. І коли ми викличемо функцію, то бачимо, що наші змінні X та Y всередині інтмейн, вони в нас не змінилися. Це тому, що ми, коли викликали функцію swap, ми передавали туди з вами копію інформації, яка зберігається в X та Y. Для того, щоб безпосередньо взаємодіяти з нашими змінами X та Y, які були створені в IntMain, ми можемо передати або посилання, яке я показував в минулому разі, або вказівник. Посилання це псевдоім'я нашого змінної, а вказівник це змінна, яка зберігає адресу на цих змінних.
Повертаємо знову зірки, компілюємо повторно, запускаємо. Все працює тепер ще раз коректно. Ось такий спосіб застосування нашого вказівника. Рекомендуємо і виконуємо наступну роботу.
Напишіть функцію, яка приймає два вказівника на цій числі, обмінюючи їх значенням. Ну, ми це вже тільки що зробили. Цю роботу ми зараз умову перекладемо сюди, для того, щоб коли ви відкрите файл, ви мали змогу зрозуміти, яке завдання ми виконували.
Гаразд, завдання ми виконали одне і друге. Надію, що ви також трішки зрозуміли, що таке вказівник. Зараз детальніше ще раз поясню, які можна дії виконувати взагалі з вказівником.
Якщо це змінна, відповідно, ми не тільки можемо робити операцію присвоєвання адрес, ми з вказівником можемо виконувати деякі і арифметичні дії. Які можна виконувати арифметичні дії? Це додавання, віднімання, інкремент і декремент. От такі дії ми можемо виконувати з нашим вказівником. Ми не можемо виконувати з вказівником порівняння.
більше-менше, равно-неравно і так далі. Ми можемо виконувати певні дії, такі як збільшити наш вказівник на 1, або зменшити на 1, або, наприклад, просто додати плюс 1. Зараз покажу декілька прикладів, і ви зараз розумієте, чому можна виконувати ці дії. Пишемо знову int main, відкриваємо фейерверні дужки, створюємо... Масив фігурні дужки.
Ініціалізуємо масив нашими значеннями. Давайте знову х буде 5. Чому ми створюємо масив? Тому що такі дії арифметичні додавання віднімання плюс-плюс, мінус-мінус вказівника можна використовувати тільки в тому випадку, якщо вказівник вказує на масив.
Такі дії ще називаються арифметика вказівника. Тепер створимо вказівник, пишемо int 0.5r равно rr. Бачите, ми цього разу знову не використовуємо амперсант, це тому що, ще раз наголошую, назва нашого масива одновимірного або двовимірного, це є і вказівник, який зберігає адресу на перший елемент нашого масиву.
Тому коли я прописав просто int зірочка 5r равно rr, то я з вами поклав адресу, яку зберігається в rr в 5r. Як бачите, цього разу ми відразу при створенні нашого вказівника його ініціалізуємо якимось значенням. Що далі? Далі ми попробуємо, наприклад, вивести... яке значення через казівник.
Якщо я напишу просто ptr std endl.com, скомпілюємо повторно. Запустимо. Ми виводимо адресу. Давайте для наглядності ми зараз також виведемо просто RRA. Компілюємо.
Запускаємо. Бачимо, що значення нас однакові. Дійсно так, що RRA в собі зберігає адресу на перший елемент нашого масиву. І PTR зберігає адресу на елемент першого масиву. Якщо ж нам тепер отримати доступ до якогось елемента, якщо вони вказують на перший елемент, то, можливо, нам треба додати зірку сюди, до підтєр, і ми, можливо, виведемо значення першого елемента.
Скомпілюємо, запустимо. Дійсно, це так, ми вивели значення 1, так як перший елемент, відповідно, це в нас от він, і там значення 1. Цікаво, як же ж нам отримати доступ через назву нашого масиву до першого елемента. А тут потрібно трішки по-іншому це робити, наприклад, RR-index 0. Запускаємо 1 і 1. Окей, супер, трішки тепер є розуміння, що назва нашого масиву це і є вказівник.
І 5R може відповідно вказувати на наш масив, як в попередніх прикладах я вам показував. Що тепер далі? Я говорив, що ми будемо зараз затисовувати з вами арифметичні оператори, так? Яким чином ми можемо це зробити? Якщо ми можемо використовувати з назвою нашого масиву індексацію і таким чином отримувати доступ до якихось конкретних елементів, таку ж саму дію можна і проробити з казівником, використовуючи індексацію, але можна і по-іншому застосувати доступ до якогось конкретного елемента.
Яким чином? Наприклад, я хочу через казівник отримати доступ до мого елемента під індексом №2. Пригадуємо, що елементи масиву в нас починаються 0, 1, 2. Відповідно, я хочу отримати до цього елемента доступ через вказівник. Як я це роблю? Пишу знову std cout, відкриваю кролі дужки, пишу ptr плюс 2. Якщо це в нас індекс 2, відповідно ми рахуємо два кроки.
Якщо вказник вказує на перший елемент, нам треба зробити два кроки вперед для того, щоб з вами отримати доступ до елемента під індексом 2. Один крок, другий крок. std end Компілюємо, запускаємо. Ми виводимо якусь адресу, так?
Як нам дізнатися, чи це вірна адреса цього елемента? Ми скопіюємо цей верхній рядок, помістимо нижче під вказівник, ці попередні два закоментуємо і поставимо перед rarampersand. Отримуємо адресу нашого елемента, адресу комірки, де зберігається Значення 3, точніше адресу комірки під індексом №2.
Компілюємо повторно, запускаємо, RAR, йдемо на адреси, адреси у нас відрізняються. Чому? Тому що ми не змінили ще індекс. Ставимо індекс 2, компілюємо повторно, запускаємо знову.
Тепер цього разу адреси вірні. Тобто ми отримали адресу елемента під індексом 2. Якщо ми бачимо, що на рядку 83 ми використовуємо вказівник плюс 2, тобто така дія також буде рівноцінна цій дії. Тобто ми можемо тепер через вказівник, відповідно, рухатися по елементам нашого масиву і звернутися до якогось конкретного елемента нашого масиву.
Але таким чином ми отримаємо адресу. А як же вивести значення, на яке вказує наш вказівник, прописавши під R плюс 2? Тут потрібно взяти цю.
дію у круглі дужки і перед круглими дужками написати зірку. Таким чином ми говоримо, що ми хочемо подивитися на елемент під індексом №2 і ми хочемо не подивитися не адресу цього елемента, а ми хочемо подивитися, яке там значення. І використовуємо дію розмінування. Компілюємо повторно, запускаємо, виводимо значення 3. От такі способи в нас є.
при роботі з казівником для того, щоб взаємодіяти з конкретним елементом нашого масиву. Це в нас використовується оператор додавання, тобто можна додавання, віднімання використовувати. Але також говорив, що можна використовувати і інкремент, і декремент. Як працює інкремент, і декремент? Треба розкоментувати знову цей приклад.
Тут відбувається що в нас? Ще раз давайте проговоримо. Тут відбувається що в нас? Ми з вами тут отримуємо доступ, але в казівник...
не змінює свою адресу вказівник вказує у нас на перший елемент тобто якщо я знов повторно виведу свій вказівник Давайте знову і скупіюємо цей ряд Розкоментуємо, компілюємо. 3 і 1. Ми хоча і отримали доступ до елемента під індексом №2 і вивели там значення, яке зберігається, але адресу нашого вказівника ми не змінювали. Вказівник до сих пір вказує в нас на перший елемент нашого масиву. Але якщо тепер ми будемо використовувати інкремент і декремент, std, c, a, ptr++ std endel І тепер давайте виведемо std cout зірочка ptr std endel Компілюємо, запускаємо 3, це в нас тут ми отримали доступ Потім ми пересвічили, що вказівник до сих пір зберігає адресу на перший елемент Далі ми з вами виводимо адресу першого елемента і потім ми виводимо значення 2. Тому що ми з вами тільки що зробили що?
Ми фактично з вами передвинули наш вказівник з першого елемента на другий. І поклали наш вказівник тепер адресу не першого елемента, а другого елемента. І наш вказівник тепер вказує на другий елемент.
На індекс 1, там де зберігається значення 2. Цікаво буде, якщо ми з вами от попробуємо застосувати знов таку дію, яку ми виконували на рядку №83. Після збільшення, тобто, як бачите, вказівник, використовуючи інкремент і декремент, ми пересуваємо наш вказівник на конкретний наступний елемент, або наперед, або назад. Можна і перед, і назад.
Таким чином ми можемо рухатись от по нашим елементам. А використовуючи арифметику, ми з вами просто хочемо подивитися... на декілька кроків вперед, що знаходиться в тій комірці.
Відповідно, ми можемо і подивитися, і змінити, але адреса нашого вказівника не змінюється. Якщо він вказує на якесь поточне значення, він буде і вказувати, тобто ми не змінюємо таким чином адресу нашого вказівника. А використовуючи безпосередньо плюс-плюс і мінус-мінус, ми тут вже змінюємо адресу нашого вказівника. Ми його якби або переміщаємо вперед, або переміщаємо назад. Якщо ми перемістили наш вказівник і попробуємо до нього застосувати знову таку ж саму дію, то ми з вами отримаємо доступ до елемента під індексом №3, в якому зберігається значення 4. Чому?
Тому що ми з вами ж передвинули вказівник на один крок вперед. Ми тепер знаходимося на цій позиції. І я знову говорю, глянь, будь ласка, на два кроки вперед. Рахуємо один крок, наступний крок. І ми з вами отримаємо доступ до елемента під індексом №3, де зберігається значення 4. І коли ми з вами робимо розмінування, тобто ми хочемо подивитися, яке там значення зберігається, то ми виводимо з вами значення 4. От самі прості способи.
Ну, якби самі прості, звісно, це не самі прості будуть способи, але все ж таки є певні способи. Застосування арифметичних операторів з нашим вказівником. Їх можна використовувати, але їх рідко використовують.
Саме частіше, якщо ми використовуємо вказівник на наш масив, то використовується індексація. Вона саме проста для розуміння. Це так, як ми працювали з масивом одновимірним або двохвимірним. Просто опишемо назву нашого вказівника і використовуємо з вами індекс.
Але це буде рівноцінно тому, що ми прописали от на рядку 89. Якщо я напишу std cout ptr2 std nl.com, компілюємо, запускаємо, виводимо 4 і 4. Тобто, отакі дві дії будуть однакові, але така дія називається арифметика, так як ми застосуємо якийсь арифметичний оператор, арифметика вказівника. А тут використовується індексація. Індексацію, звісно, легше використовувати.
Але не забувайте, що ви маєте можливість і, відповідно, якось рухати ваш казівник на одну позицію вперед, або, наприклад, назад рухати ваш казівник, переставляти на іншу позицію вперед. Тому що якщо ви просто будете використовувати індексацію, то пам'ятайте про те, що коли ви робите присвоювання, то ваш казівник буде вказувати на перший елемент вашого масиву. Завжди на перший елемент вашого масиву.
І використовуючи індексацію, ви не перезаписуєте адресу наступного елемента. Ви просто хочете подивитися. на крок вперед, на два кроки вперед, на три кроки вперед, на i кроків вперед, якщо буде використовувати ПТР квадратні дужки i всередині циклу for при роботі з масивом. Гаразд, на цьому все.
Я вам дякую і до наступної зустрічі.