- •1.1 Перші кроки
- •1.2 Змінні й арифметичні вирази
- •1.3 Твердження for
- •1.4 Символічні константи
- •1.5 Ввід і вивід знаків
- •1.5.1 Копіювання файла
- •1.5.2 Відлік символів
- •1.5.3 Відлік рядків
- •1.6 Масиви
- •1.7 Функції
- •1.8 Аргументи - виклик за значенням
- •1.9 Символьні масиви
- •1.10 Зовнішні змінні й область дії
- •2.1 Назви змінних
- •2.2 Типи даних і розміри
- •2.3 Константи
- •2.4 Оголошення
- •2.5 Арифметичні операції
- •2.6 Реляційні та логічні оператори
- •2.7 Перетворення типів
- •2.8 Оператори приросту та спаду
- •2.9 Розрядні оператори
- •2.10 Оператори та вирази присвоєння
- •2.11 Вирази умов
- •2.12 Пріоритет і послідовність обчислення
- •3.1 Вирази та блоки
- •3.3 Else if
- •3.4 Switch
- •3.5 Цикли while та for
- •3.6 Цикли do-while
- •3.7 Break і continue
- •3.8 Goto та мітки
- •4.1 Основні знання про функції
- •4.2 Функції, які не повертають цілих
- •4.3 Зовнішні змінні
- •4.4 Правила області дії
- •4.5 Файли заголовка
- •4.6 Статичні змінні
- •4.7 Регістрові змінні
- •4.8 Структура блоків
- •4.10 Рекурсія
- •4.11 Препроцесор c
- •4.11.1 Включення файлів
- •4.11.2 Заміна макросів
- •4.11.3 Обумовлене включення файлів
- •5.1 Покажчики й адреси
- •5.2 Покажчики й аргументи функцій
- •5.3 Покажчики та масиви
- •5.4 Арифметика адрес
- •5.5 Покажчики на символи та функції
- •5.6 Масив покажчиків; покажчики на покажчики
- •5.7 Багатовимірні масиви
- •5.8 Ініціалізація масиву покажчиків
- •5.9 Покажчики в порівнянні з багатовимірними масивами
- •5.10 Аргументи командного рядка
- •5.11 Покажчики на функції
- •5.12 Складні оголошення
- •6.1 Основні поняття про структури
- •6.2 Структури та функції
- •6.3 Масиви структур
- •6.4 Покажчики на структури
- •6.5 Структури зі зворотнім звертанням
- •6.6 Пошук по таблиці
- •6.7 Typedef
- •6.8 Сполуки
- •6.9 Розрядні поля
- •7.1 Стандартний ввід і вивід
- •7.2 Форматований вивід - printf
- •7.3 Списки аргументів довільної довжини
- •7.4 Форматований ввід - scanf
- •7.5 Доступ до файлів
- •7.6 Обробка помилок - stderr і exit
- •7.7 Ввід і вивід рядків
- •7.8 Додаткові функції
- •7.8.1 Операції з ланцюжками
- •7.8.2 Перевірка і перетворення класів символів
- •7.8.3 Ungetc
- •7.8.4 Виконання команд
- •7.8.5 Керування пам'яттю
- •7.8.6 Математичні функції
- •7.8.7 Генератор випадкових чисел
- •8.1 Дескриптори файлів
- •8.2 Низькорівневий ввід/вивід - read і write
- •8.3 Open, creat, close, unlink
- •8.4 Довільний доступ - lseek
- •8.5 Приклад: втілення fopen і getc
- •8.6 Приклад - перелік вмісту каталогів
- •8.7 Приклад - розподільник пам'яті
5.8 Ініціалізація масиву покажчиків
Уявіть собі завдання по написанню функції month_name(n), яка би повертала покажчик на символьний ланцюжок, який містить назву n-нного місяця. Це являє собою ідеальне примінення внутрішнього статичного масиву. month_name включатиме приватний масив символьних ланцюжків, і повертатиме покажчик на відповідний, коли викликати її. Цей розділ демонструє, як ініціалізувати такий масив назв.
Синтаксис є подібним до попередніх ініціалізацій:
/* month_name: повертає назву n-нного місяця */
char *month_name(int n)
{
static char *name[] = {
"Illegal month",
"January", "February", "March",
"April", "May", "June",
"July", "August", "September",
"October", "November", "December"
};
return (n < 1 || n > 12) ? name[0] : name[n];
}
Оголошення name являється масивом символьних покажчиків, таким самим як lineptr у прикладі з сортуванням. Ініціалізатором служить список символьних ланцюжків; кожному з них призначено відповідне положення в масиві. Символи i-ного ланцюжка розміщено в певному місці і покажчик на них збережено в name[i]. Оскільки розмір масиву name не вказано, компілятор сам порахує ініціалізатори і заповнить розмір правильним числом.
5.9 Покажчики в порівнянні з багатовимірними масивами
Новачки C, часом, плутаються з відмінністю між двовимірним масивом і масивом покажчиків, такому як name, у вищенаведеному прикладі. Маючи два визначення
int a[10][20];
int *b[10];
a[3][4] і b[3][4], обидва, являються синтаксично-правильними посиланнями на певну одиницю. Але a, це справжній двовимірний масив: під нього відведено 200 положень розміруint, і використовується традиційне прямокутне обчислення індексів 20*row+col для того, щоб віднайти елемент a[row,col]. Проте, у випадку з b, таке визначення виділяє тільки 10 покажчиків, не ініціалізуючи їх; ініціалізацію потрібно здійснити явно, або статично, або ж за допомогою коду. Припускаючи, що кожний елемент b вказує на масив з двадцяти елементів, тоді буде відведено місце під 200 int, плюс десять комірок для покажчиків. Важливою перевагою масиву покажчиків є те, що рядки масиву можуть бути різноманітного розміру. Тобто, кожний елемент b не обов'язково повинен вказувати на вектор з двадцяти елементів; деякі можуть показувати на два елементи, інші — на п'ятдесят, а деякі — на жоден. Хоч ми й обійшлися в цій дискусії цілими числами, найчастіше використання масиву покажчиків полягає в збереженні символьних ланцюжків різноманітної довжини, як у функції month_name. Порівняйте оголошення і малюнок для масиву покажчиків
char *name[] = { "Illegal month", "Jan", "Feb", "Mar" };
name:
+-----+ +-----------------+
| *--|-----> | Illegal month\0 |
| | +-----------------+
| | +-------+
| *--|-----> | Jan\0 |
| | +-------+
| | +-------+
| *--|-----> | Feb\0 |
| | +-------+
| | +-------+
| *--|-----> | Mar\0 |
+-----+ +-------+
з аналогічними для двовимірного масиву:
char aname[][15] = { "Illegal month", "Jan", "Feb", "Mar" };
aname:
+----------------------------------------------------------------+
| Illegal month\0 Jan\0 Feb\0 Mar\0 |
+----------------------------------------------------------------+
0 15 30 45
Вправа 5-9. Перепишіть наново функції day_of_year і month_day із покажчиками замість індексів.
