C масиви і покажчики нерозривно пов’язані. Ви не зможете писати ефективний код, не розуміючи їхнього взаємозв’язку. На освоєння цього витрачається час. Але нагорода – миттєвий контроль над пам’яттю – приходить одразу.
Розглянемо базовий приклад. Ви оголошуєте два цілих масиву розміром десять.
`
Спробуйте скомпілювати цей код. Він не скомпілюється. Ви не можете присвоїти один масив іншому за допомогою знаку рівності. C не підтримує копіювання блоків даних через оператори присвоєння. Щоб скопіювати a у b, потрібно пройти циклом по кожному елементу.
`
Ви могли б стиснути цей цикл в один рядок, використовуючи кому, але це погіршить читання. Стандартний підхід — використовувати функцію memcpy із заголовного файлу string.h. Вона ефективно виконує побайтове копіювання.
Невдача присвоєння b=a розкриває фундаментальне правило. У C змінні масиву це не самі масиви. Це фіксовані покажчики. a та b — це постійні ідентифікатори, які вказують на початкову адресу своїх блоків пам’яті. a вказує на a[0]. b вказує на b[0]. Ці адреси незмінні. Ви не можете перенаправити ім’я змінної на інше місце в пам’яті. Саме тому привласнення завершується помилкою. Компілятор розглядає ім’я масиву як константний покажчик.
Оскільки ім’я власне є вказівником, ви можете використовувати арифметику покажчиків для доступу до даних. Тут синтаксис стає потужним інструментом.
`
Тут p – це змінна-покажчик. Ви можете присвоїти адресу масиву a змінній p. Вираз p=a копіює адресу. Тепер p містить те саме значення, що й ім’я масиву a. Розіменування p за допомогою ‘*p’ повертає перший елемент. Висновок дорівнюватиме нулю.
Ця різниця важлива, тому що змінні-покажчики можна змінювати. Ви можете змусити p вказувати на a[1] або a[5], використовуючи арифметику. Саме ім’я масиву залишається закріпленим на початку. Ця гнучкість дозволяє функціям перебирати пам’ять без копіювання великих структур даних. Це основа продуктивності на низькому рівні C.
Розуміння цього зв’язку запобігає тонким помилкам. Вона пояснює, чому деякі функції приймають покажчики замість синтаксису масивів. Вона прояснює структуру пам’яті. Нехтуйте цим знанням, і ви боротиметеся з помилками сегментації або ненавмисними перезаписами даних. Освойте його, і ви точно бачитимете, що робить машина.
Синтаксис може спочатку здатися незвичним. Подвійне значення квадратних дужок і зірочок збиває з пантелику новачків. Але коли модель стає зрозумілою, абстракція зникає. Залишаються лише адреси та значення. Нічого більше.
Чи варто цих зусиль? Код стає швидшим. Витрата пам’яті знижується. Ви отримуєте прямий доступ до операцій на рівні обладнання. Більшість програм на C покладаються

Ви можете безпосередньо присвоїти змінну-масив покажчику, тому що «під капотом» вони по суті є одним і тим самим.
p=a; працює не завдяки магії, а тому що a розпадається до покажчика. Зокрема, він вказує на адресу пам’яті першого елемента масиву (з індексом 0). Оскільки цей елемент є цілим числом, a діє як покажчик одне ціле число (int). Оголошення p як вказівника на ціле число та привласнення йому значення a — це просто надання двом змінним загальної адреси. Натомість ви могли б написати p=&a[0];. Результат буде ідентичним.
Як тільки p пов’язується з початком a, ви маєте можливість переміщатися. Імена масивів, такі як a, є константами; це фіксовані адреси, які не можна змінити. Покажчики, такі як p, поводяться інакше. Ви можете переміщувати їх за допомогою арифметики покажчиків.
Тут C виявляє свою винахідливість.
Коли ви пишете p++;, компілятор не просто додає один байт до адреси. Він знає, що p свідчить про ціле число. Натомість він додає sizeof(int) байт, потрапляючи точно на наступний елемент. Якби p вказував на структуру довжиною 100 байт, p++ перемістив покажчик на 100 байт вперед. C виконує всю математику за вас. Ви просто переміщаєте вказівник.
Копіювання масивів без індексів
Ви можете скопіювати один масив в інший за допомогою цих покажчиків. Замість стандартного циклу з індексами:
`
Ви можете використовувати покажчики:
`
Це багатослівно. Це можна стиснути.
`
Або стиснути все в один рядок.
`
Тут оператори виконують тяжку роботу. Оператор * має більш високий пріоритет, ніж ++, але постінкремент відбувається після отримання значення. Отже, *p++ отримує поточне значення, та був переміщає покажчик. *q++ робить те саме для місця призначення. Присвоєння відбувається між цими діями. Це компактно. Це швидко. Але це також легко неправильно прочитати, якщо не бути уважним.
Небезпечна зона
Що станеться, якщо ви виведете p чи q за межі масиву?
З вас не зупинить.
Компілятор припускає, що ви знаєте, що робите. Він продовжуватиме збільшувати покажчики, копіюючи дані на згадку, яка не належить масиву. Ви можете перезаписати інші змінні. Ви можете зіпсувати стек. Ви можете викликати помилку програми пізніше, в місці, не пов’язаному з помилкою.
Саме тому перевірка кордонів C виконується вручну. Мова довіряє вам. Коли ви виходите за межі правил, ви платите за це ціну.
Передача масивів у функції
Ви можете передавати масиви функції двома способами. Вони виглядають по-різному, але поводяться аналогічно.
Розглянемо функцію, яка виводить масив:
`
Або версія із покажчиками:
`
Параметр nia (кількість елементів у масиві) є обов’язковим. Масиви C не зберігають свій розмір разом з собою. Функції необхідно знати, коли зупинитися.
В обох випадках ви передаєте вказівник на початок масиву, а не


































































