Урок №78. Фіксовані масиви

  Юрій  | 

  Оновл. 28 Чер 2020  | 

 390

Цей урок є продовженням попереднього уроку про масиви в С++.

Ініціалізація фіксованих масивів

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

Однак це не зовсім зручно, особливо коли масив великий.

На щастя, C++ підтримує більш зручний спосіб ініціалізації масивів за допомогою списку ініціалізаторів. Наступний приклад еквівалентний вищевказаному прикладу:

Якщо в цьому списку ініціалізаторів більше, ніж може містити масив, то компілятор видасть помилку.

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

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

5
7
9
0
0

Отже, щоб проініціалізувати всі елементи масиву значенням 0, потрібно:

У C++11 замість цього може використовуватися синтаксис uniform-ініціалізації:

Довжина масиву

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

Наступних два рядки коду виконують одне і те ж:

Це не тільки заощадить час, але також вам не доведеться оновлювати довжину масиву, якщо ви захочете додати або видалити елементи пізніше.

Масиви і перерахування

Одна з основних проблем з документацією в масивах полягає в тому, що цілочисельні індекси не надають ніякої інформації програмісту про їх значення. Розглянемо клас з 5 учнів:

Що представлено елементом testScores[3]? Незрозуміло!

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

Тепер-то зрозуміло, що являє собою кожний з елементів масиву. Зверніть увагу, що був доданий додатковий енумератор з ім’ям MAX_STUDENTS. Він використовується під час оголошення масиву для гарантії того, що масив має коректну довжину (розмір повинен бути на одиницю більше найбільшого індексу). Це корисно як в цілях документації, так і в тому, що масив буде автоматично змінений, якщо додати ще один енумератор:

Зверніть увагу, цей трюк працює тільки в тому випадку, якщо ви не змінюєте значення енумераторів вручну!

Масиви і класи enum

Класи enum не мають неявної конвертації в цілочисельний тип, тому, якщо ви спробуєте зробити наступне:

То отримаєте помилку від компілятора. Це можна вирішити, використовуючи оператор static_cast для конвертації енумератора в ціле число:

Проте це також не дуже зручно, тому краще використовувати стандартне перерахування всередині простору імен:

Передача масивів у функції

Хоча передача масиву в функцію на перший погляд виглядає так само, як передача звичайної змінної, але “під капотом” C++ обробляє масиви трохи інакше.

Коли звичайна змінна передається по значенню, то C++ копіює значення аргументу в параметр функції. Оскільки параметр є копією, то зміна значення параметру не змінює значення вихідного аргументу.

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

Наступний приклад добре ілюструє цю концепцію:

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

before passValue: 1
after passValue: 1
before passArray: 1 4 6 8 10
after passArray: 10 8 6 4 1

У вищенаведеному прикладі значення змінної value не змінюється в функції main(), так як параметр value в функції passValue() був лише копією фактичної змінної value. Однак, оскільки масив в параметрі функції passArray() є фактичним масивом, то passArray() безпосередньо змінює значення елементів!

Примітка: Якщо ви не хочете, щоб функція змінювала значення елементів масиву, переданого в неї в якості параметра, то потрібно зробити масив константним:

Оператор sizeof і масиви

Оператор sizeof можна використовувати і з масивами: він повертає загальний розмір масиву (довжина масиву помножена на розмір одного елемента) в байтах. Зверніть увагу, що через те, як С++ передає масиви у функції, ця операція не буде коректно виконана з масивами, переданими в функції! Наприклад:

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

32
4

З цієї причини будьте обережні з використанням оператора sizeof з масивами!

Визначення довжини фіксованого масиву

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

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

The array has 8 elements

Як це працює? По-перше, розмір всього масиву дорівнює довжині масиву, помноженої на розмір одного елементу. Формула: розмір масиву = довжина масиву * розмір одного елементу.

Використовуючи алгебру, ми можемо змінити дане рівняння: довжина масиву = розмір масиву / розмір одного елементу. sizeof(array) — це розмір масиву, а sizeof(array [0]) — це розмір одного елемента масиву. Відповідно, довжина масиву = sizeof(array) / sizeof(array[0]). Зазвичай використовується нульовий елемент в якості елемента масиву в рівнянні, так як тільки він є єдиним елементом, який гарантовано існує в масиві, незалежно від його довжини.

Це працює тільки якщо масив фіксованої довжини, і ви виконуєте цю операцію в тій же функції, в якій оголошено масив (ми поговоримо детальніше про це у відповідних уроках).

Терміни «розмір масиву» і «довжина масиву» найчастіше використовуються для позначення довжини масиву. Тому в наступних уроках ми будемо використовувати термін «довжина» для позначення загальної кількості елементів в масиві, і термін «розмір» — коли мова буде йти про байти.

Індексування поза діапазоном масиву

Пам’ятайте, що масив довжиною N містить елементи від 0 до N-1. Отже, що станеться, якщо ми спробуємо отримати доступ до індексу масиву поза межами цього діапазону? Розглянемо наступну програму:

Тут наш масив має довжину 5, але ми намагаємося записати значення в 6-й елемент (індекс 5).

C++ не виконуватиме тут ніяких перевірок коректності вашого індексу. Таким чином, в прикладі вище значення 14 буде поміщено в комірку пам’яті, де був би 6-й елемент (якби він взагалі існував би). Але як ви вже здогадалися, це матиме свої наслідки. Наприклад, відбудеться перезапис значення іншої змінної або взагалі збій програми.

Хоча це відбувається рідше, але C++ також дозволяє використовувати від’ємний індекс, що теж може привести до небажаних результатів.

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

Тест

Завдання №1

Оголосіть масив для зберігання температури (дробове число) кожного дня в році (всього 365 днів). Ініціалізуйте масив значенням 0.0 для кожного дня.

Відповідь №1

Примітка: Якщо розмір не є обмеженням, то замість float краще використовувати double.

Завдання №2

Створіть перерахування з наступними енумераторами: chicken, lion, giraffe, elephant, duck і snake. Помістіть перерахування в простір імен. Оголосіть масив, де елементами будуть ці енумератори і, використовуючи список ініціалізаторів, ініціалізуйте кожен елемент відповідною кількістю лап певної тварини. У функції main() виведіть кількість лап у слона, використовуючи енумератор.

Відповідь №2

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

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

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

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