1. Масив — це контейнер елементів
Найімовірніше ви чули, що компʼютери можуть обробляти величезні обсяги інформації. Умовний оператор (if-else) і цикли (for, while) у цьому, звісно, допомагають. Але далеко на них не заїдеш, адже оброблювані дані потрібно десь зберігати.
На цей випадок у C#, як і майже в усіх мовах програмування, є така зручна штука, як масиви (Array). Їх іноді називають таблицями.
Масив — це спеціальний об’єкт, у якому можна зберігати не одне значення, а декілька.
Якщо раніше ми порівнювали змінну з коробкою (де можна зберігати якесь значення), то масив — це радше коробка, поділена всередині на секції. Кожна секція в «коробці‑масиві» має свій номер. Нумерація, звісно, з нуля…
Або можна провести ще одну аналогію. Порівняймо звичайний житловий будинок і багатоповерхівку. Звичайний будинок займає одна сімʼя, а багатоповерхівка поділена на квартири. Щоб написати листа сімʼї, яка живе у звичайному будинку, потрібно вказати його унікальну адресу. А щоб написати листа сімʼї, яка мешкає в квартирі, потрібно вказати унікальну адресу будинку і ще номер квартири.
Отже, змінна‑масив — це змінна‑багатоповерхівка. У ній можна зберігати не одне значення, а декілька. У такій змінній є декілька квартир (комірок), до кожної з яких можна звернутися за її номером (індексом).
Для цього після імені змінної у квадратних дужках потрібно вказати індекс комірки, до якої звертаєтеся. Це досить просто:
array[індекс] = значення;
Де array — це імʼя змінної‑масиву, індекс — номер комірки в масиві, а значення — значення, яке ми хочемо занести у вказану комірку.
Але спершу розберімося, як створювати масиви.
2. Створення масиву елементів у C#
Припустімо, вашій програмі потрібно десь зберігати 100 цілих чисел. Найімовірніше для цього підійде масив. Як же його створити?
Якби ми хотіли зберігати одне ціле число, нам підійшов би тип int. Якщо ж потрібно зберігати 100 цілих чисел, імовірно, нам потрібен масив типу int. Ось як виглядатиме код для його створення:
int[] array = new int[100];
Розберімося, що тут відбувається.
Як ви вже, можливо, здогадалися, зліва від знака рівності маємо оголошення змінної з іменем array і типу int[]. Після типу int йдуть квадратні дужки, які ніби натякають, що в «коробках» цього типу можна буде зберігати не одне значення, а декілька.
Праворуч від знака рівності — «створення об’єкта» (слово new) на 100 елементів (комірок) типу int. Теж не надто складно.
Якби ми хотіли, наприклад, створити масив на 20 комірок для зберігання дійсних чисел, код його створення виглядав би так:
double[] vals = new double[20];
Кількість комірок у масиві називають розміром масиву або довжиною масиву. А через здатність зберігати багато значень масиви ще називають контейнерами.
Важливий факт: розмір контейнера масиву не можна змінити після створення.
Можна створити новий масив, але довжину вже створеного контейнера змінити неможливо.
3. Робота з комірками масиву
Масиви створювати ми навчилися. Як із ними правильно працювати?
Майже так само, як і зі звичайними змінними, але після імені змінної‑масиву обов’язково потрібно вказувати номер комірки, з якою працюєте.
Нумерація комірок масиву завжди починається з нуля. Якщо у нас масив на 10 елементів, то номери (індекси) його комірок — 0..9; якщо масив на 200 елементів — 0..199. І далі за аналогією.
Приклади:
int[] a = new int[10]; // Створюємо масив на 10 елементів типу int.
a[2] = 4; // У комірку з індексом 2 записуємо значення 4.
a[7] = 9; // У комірку з індексом 7 записуємо значення 9.
a[9] = a[2] + a[5]; // У комірку з індексом 9 записуємо суму значень, які зберігаються у комірках 2
// (зберігається 4) і 5 (зберігається 0).
Ось що буде зберігатися в памʼяті після виконання цього коду:
Колонка зліва від масиву (сірим кольором) — це номери (індекси) комірок. У комірках зберігаються внесені значення: 4, 9 і 4. Одразу після створення комірки масиву заповнені нулями.
Важливо. Усі комірки масиву мають однаковий тип даних. Якщо ми створили масив рядків string, у його комірках можна зберігати лише рядки. Тип даних масиву задається під час його створення. Ні тип даних, ні довжину масиву потім змінити не можна.
4. Масиви в памʼяті
Зображення у попередніх прикладах трохи неточні.
Під час створення масивів (як і під час створення рядків) у памʼяті виділяються два блоки: один для зберігання самого масиву (контейнера), а другий — під змінну, яка зберігає його адресу. Уточнена ситуація зображена на картинці нижче:
Зеленим кольором показано масив на 10 елементів типу int і змінну типу int[], яка зберігає адресу (посилання) масиву типу int у памʼяті.
Для порівняння синім кольором позначено звичайну змінну типу int, яка зберігає значення 199.
Чимось це нагадує зберігання рядків у памʼяті, чи не так?
Саме так. І як із рядками, «змінні типу масив» можна присвоювати одна одній:
int[] a = new int[10]; // Створюємо масив на 10 елементів типу int.
a[2] = 4; // У комірку з індексом 2 записуємо значення 4.
a[7] = 9; // У комірку з індексом 7 записуємо значення 9.
int[] b = a; // У змінну b зберігаємо адресу, яка є у змінній a.
// Тепер a і b вказують на один і той самий об’єкт‑масив у памʼяті.
a[9] = b[2] + a[7]; // У комірку з індексом 9 об’єкта‑масиву записуємо суму значень,
// які зберігаються у комірках 2 (зберігається 4) і 7 (зберігається 9).
При цьому об’єкт‑масив залишатиметься там, де й був, а змінні a і b зберігатимуть однакові адреси (посилання) на один і той самий об’єкт. Дивіться ілюстрацію:
5. Робота з масивом детальніше
Масив можна створити для будь‑якого типу. Для цього лише потрібно після імені типу вказати квадратні дужки. Загальний вигляд створення масиву такий:
тип[] ім'я = new тип[кількість];
Де тип — це тип елементів (комірок) масиву, які ми зберігатимемо у масиві. Імʼя — це імʼя змінної, за яким ми звертатимемося до масиву, а кількість — це кількість комірок у масиві.
У прикладі вище наведено канонічну форму: створення змінної‑масиву і створення обʼєкта‑масиву. Насправді це дві незалежні конструкції. Можна створити змінну‑масив і обʼєкт‑масив окремо:
тип[] ім'я;
ім'я = new тип[кількість];
І ще один важливий момент
Як індекс масиву і як кількість елементів масиву можуть використовуватися змінні й навіть цілі вирази.
Приклади:
int n = 100;
int[] a = new int[n]; // Створення масиву з n елементів
int n = 100;
int[] a = new int[n * 2 + 3]; // Створення масиву на 203 елементи
int n = 100;
int[] a = new int[n];
a[n-1] = 2; // a[99] = 2;
a[n-2] = 3; // a[98] = 3;
a[n/5] = a[n-1] + a[n-2]; // a[20] = a[99] + a[98];
Вихід за межі масиву
Зверніть увагу: якщо спробувати звернутися до комірки масиву за індексом, якого в масиві немає (у нашому випадку це всі цілі числа, крім 0..99), програма аварійно завершиться з помилкою IndexOutOfRangeException — індекс за межами масиву.
6. Довжина масиву
Як ми побачили у попередньому прикладі, можна окремо створити змінну типу масив і потім десь у коді присвоїти їй значення (посилання на обʼєкт‑масив). Можна зробити навіть так:
int[] array; // Створюємо змінну‑масив типу int[]
if (a < 10) // Якщо змінна a менша за 10,
array = new int[10]; // то створити масив із 10 елементів.
else // Інакше
array = new int[20]; // створити масив із 20 елементів
І як працювати далі з таким масивом? Як дізнатися, скільки в ньому елементів?
Для цього масив має спеціальну властивість — Length. Дізнатися довжину масиву можна за допомогою такого виразу:
array.Length;
Де array — це імʼя змінної‑масиву, а Length — це імʼя властивості обʼєкта‑масиву. Значення у властивості Length змінити не можна: саму властивість Length можна читати й присвоювати її значення іншим змінним, але їй самій нічого присвоїти не можна (програма просто не скомпілюється).
Ось як можна продовжити попередній приклад:
int[] array; // Створюємо змінну‑масив типу int[]
if (a < 10) // Якщо змінна a менша за 10,
array = new int[10]; // то створити масив із 10 елементів.
else // Інакше
array = new int[20]; // створити масив із 20 елементів
for (int i = 0; i < array.Length; i++) // Цикл за всіма елементами масиву: від 0 до array.Length — 1
{
Console.WriteLine(array[i]);
}
7. Факти про масиви в C#
Підсумуймо відомі факти про масиви:
- Факт 1. Масив складається з багатьох комірок.
- Факт 2. Доступ до конкретної комірки здійснюється за її номером.
- Факт 3. Усі комірки одного типу.
- Факт 4. Початкові значення: для числових типів — 0, для посилальних — null, для типу bool — false.
- Факт 5. string[] list — це лише оголошення змінної: сам контейнер (об’єкт‑масив) ще не створено. Щоб із ним можна було працювати, потрібно створити масив (контейнер) і покласти його у цю змінну, а потім уже ним користуватися. Див. приклад нижче.
- Факт 6. Коли ми створюємо об’єкт‑масив (контейнер), потрібно вказати, якої він довжини — скільки в ньому комірок. Це робиться командою виду: new TypeName[n];
- Факт 7. Довжину масиву можна дізнатися через властивість .Length.
- Факт 8. Після створення масиву не можна змінити ані тип його елементів, ані їхню кількість.
string s; // s дорівнює null
string[] list; // list дорівнює null
list = new string[10]; // Змінна list зберігає посилання на об’єкт‑масив рядків із 10 елементів.
int n = list.Length; // n дорівнює 10
list = new string[0]; // Тепер list містить масив із 0 елементів.
// Масив є, але зберігати елементи він не може.
list = null;
Console.WriteLine(list[1]); // Буде згенеровано помилку — програма аварійно завершиться.
// list містить нульове посилання — null
list = new string[10];
Console.WriteLine(list[10]); // Буде згенеровано помилку — вихід за межі масиву.
// Якщо list містить 10 елементів/комірок, то їхні дозволені індекси: 0 1 2 3 4 5 6 7 8 9 — усього 10.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ