C Покажчики та масиви
Покажчики та масиви
Ви також можете використовувати покажчики для доступу до масивів.
Розглянемо наступний масив цілих чисел:
Приклад
int myNumbers[4] = {25, 50, 75, 100};
З розділу масиви ви дізналися, що ви можете перебирати елементи масиву за допомогою циклу for
:
Приклад
int myNumbers[4] = {25, 50, 75, 100};
int i;
for (i = 0; i < 4; i++) {
printf("%d\n", myNumbers[i]);
}
Результат:
25
50
75
100
Замість того, щоб друкувати значення кожного елемента масиву, давайте надрукуємо адресу пам’яті кожного елемента масиву:
Приклад
int myNumbers[4] = {25, 50, 75, 100};
int i;
for (i = 0; i < 4; i++) {
printf("%p\n", &myNumbers[i]);
}
Результат:
0x7ffe70f9d8f0
0x7ffe70f9d8f4
0x7ffe70f9d8f8
0x7ffe70f9d8fc
Зауважте, що останній номер адреси пам’яті кожного елемента різний, з додаванням 4.
Це тому, що розмір типу int
зазвичай становить 4 байти, пам’ятайте:
Приклад
// Створіть змінну int
int myInt;
// Отримайте розмір пам’яті int
printf("%lu", sizeof(myInt));
Результат:
4
Отже, з прикладу адреси пам’яті вище ви можете бачити, що компілятор резервує 4 байти пам’яті для кожного елемента масиву, що означає, що весь масив займає 16 байт (4 * 4) пам’яті:
Приклад
int myNumbers[4] = {25, 50, 75, 100};
// Отримайте розмір масиву myNumbers
printf("%lu", sizeof(myNumbers));
Результат:
16
Як покажчики пов’язані з масивами?
Добре, то який зв’язок між покажчиками та масивами? Що ж, у C ім’я масиву насправді є покажчиком на перший елемент масиву.
Збентежені? Давайте спробуємо зрозуміти це краще та знову використаємо наш приклад адреси пам’яті вище.
Адреса пам’яті першого елемента збігається з ім’ям масиву:
Приклад
int myNumbers[4] = {25, 50, 75, 100};
// Отримайте адресу пам’яті масиву myNumbers
printf("%p\n", myNumbers);
// Отримайте адресу пам’яті першого елемента масиву
printf("%p\n", &myNumbers[0]);
Результат:
0x7ffe70f9d8f0
0x7ffe70f9d8f0
Це фактично означає, що ми можемо працювати з масивами через покажчики!
Як? Оскільки myNumbers є покажчиком на перший елемент у myNumbers, ви можете використовувати оператор *
для доступу до нього:
Приклад
int myNumbers[4] = {25, 50, 75, 100};
// Отримати значення першого елемента в myNumbers
printf("%d", *myNumbers);
Результат:
25
Щоб отримати доступ до решти елементів у myNumbers, ви можете збільшити покажчик/масив (+1, +2 тощо):
Приклад
int myNumbers[4] = {25, 50, 75, 100};
// Отримайте значення другого елемента в myNumbers
printf("%d\n", *(myNumbers + 1));
// Отримайте значення третього елемента в myNumbers
printf("%d", *(myNumbers + 2));
// і так далі
Результат:
50
75
Або переберіть його:
Приклад
int myNumbers[4] = {25, 50, 75, 100};
int *ptr = myNumbers;
int i;
for (i = 0; i < 4; i++) {
printf("%d\n", *(ptr + i));
}
Результат:
25
50
75
100
Також можна змінювати значення елементів масиву за допомогою покажчиків:
Приклад
int myNumbers[4] = {25, 50, 75, 100};
// Змініть значення першого елемента на 13
*myNumbers = 13;
// Змініть значення другого елемента на 17
*(myNumbers +1) = 17;
// Отримайте значення першого елемента
printf("%d\n", *myNumbers);
// Отримайте значення другого елемента
printf("%d\n", *(myNumbers + 1));
Результат:
13
17
Такий спосіб роботи з масивами може здатися дещо надмірним. Особливо з простими масивами, як у прикладах вище. Однак для великих масивів набагато ефективнішим може бути доступ до масивів і маніпулювання ними за допомогою покажчиків.
Також вважається, що доступ до двовимірних масивів за допомогою покажчиків є швидшим і легшим.
А оскільки рядки насправді є масивами, ви також можете використовувати покажчики для доступу до рядків.
Поки що чудово, що ви знаєте, як це працює. Але, як ми вказали в попередньому розділі: з покажчиками слід поводитися обережно, оскільки можна перезаписати інші дані, що зберігаються в пам’яті.