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

  Юрій  | 

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

 531

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

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

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

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

На щастя, мова 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 Зірок (6 оцінок, середня: 5,00 з 5)
Loading...

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

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