- •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 Приклад - розподільник пам'яті
4.1 Основні знання про функції
Для початку, сплануймо та напишемо програму виводу кожного рядка вводу, який містить певний «зразок» або ланцюжок знаків. (Своєрідну імітацію програми grep Юнікса.) Так, наприклад, пошук зразка, що складається з літер «ould» у наборі рядків
Ah Love! could you and I with Fate conspire
To grasp this sorry Scheme of Things entire,
Would not we shatter it to bits -- and then
Re-mould it nearer to the Heart's Desire!
видав би нам
Ah Love! could you and I with Fate conspire
Would not we shatter it to bits -- and then
Re-mould it nearer to the Heart's Desire!
Цю роботу можна акуратно розбити на три частини:
while (ще є рядок)
if (рядок містить зразок)
вивести рядок
Безперечно, ми могли би помістити увесь код такої програми в main, але кращим виходом буде використати цю струкруру на свою користь, розбивши кожну її частину на окремі функції. З малими частинами набагато легше впоратись, ніж з однією великою, оскільки деталі, що не стосуються справи, можна сховати всередині функцій, і можливість небажаних взаємодій буде зведено нанівець. Також, частини можуть виявитись корисними для інших програм.
«Ще є рядок» — це getline — функція, яку ми написали у Розділі 1 і «вивести рядок» — цеprintf, яку хтось створив вже для нас. Це означає, що нам залишилось написати функцію, яка вирішувала б, чи рядок містить ланцюжок, який збігається зі зразком.
Ми можемо вирішити це завдання шляхом написання функції strindex(s,t), яка повертає положення, або індекс у ланцюжку s, де починається ланцюжок t, або -1, якщо s не містить t. Оскільки масиви в C починаються з позиції 0, їхні індекси можуть бути або нульовими, або додатніми, тож від'ємне число, як от -1 — зручне для сигналізування невдачі. Якщо нам пізніше потрібне буде більш витончене порівняння зі зразком, ми можемо замінити тільки функціюstrindex, тоді як решта коду може залишитись незмінною. (Стандартна бібліотека передбачає функцію strstr, аналогічну strindex, за винятком того, що вона повертає покажчик замість індексу.)
Маючи усе спланованим, заповнення деталей програми — досить прямолінійне. Нижче наведено увесь код, тож ви можете побачити, як частини взаємодіють разом. Поки що, зразок, за яким здійснюється пошук, складається з буквенного ланцюжка, що не являється найуніверсальнішим механізмом. Згодом, ми дійдемо до обговорювання того, як ініціювати символьні масиви, а вРозділі 5 ми продемонструємо, як зробити зі зразка параметр, який можна задати під час обігу програми. Ця версія getline трохи відрізняється від використаної в Розділі 1; можливо буде повчальним, якщо ви порівняєте їх.
#include <stdio.h>
#define MAXLINE 1000 /* максимальна довжина рядків */
int getline(char line[], int max);
int strindex(char source[], char searchfor[]);
char pattern[] = "ould"; /* зразок, який шукатиметься */
/* знаходить всі рядки, що збігаються зі зразком */
main()
{
char line[MAXLINE];
int found = 0;
while (getline(line, MAXLINE) > 0)
if (strindex(line, pattern) >= 0) {
printf("%s", line);
found++;
}
return found;
}
/* getline: розміщає рядок у s, повертає довжину */
int getline(char s[], int lim)
{
int c, i;
i = 0;
while (--lim > 0 && (c=getchar() != EOF && c != '\n')
s[i++] = c;
if (c == '\n')
s[i++] = c;
s[i] = '\0';
return i;
}
/* strindex: вертає індекс t у s, або -1, якщо t не знайдено */
int strindex(char s[], char t[])
{
int i, j, k;
for (i = 0; s[i] != '\0'; i++) {
for (j=i, k=0; t[k]!='\0' && s[j]==t[k]; j++, k++)
;
if (k > 0 && t[k] == '\0')
return i;
}
return -1;
}
Кожне визначення функції має форму
тип_повернення назва_функції(оголошення аргументів)
{
оголошення та твердження
}
Окремі частини можуть бути відсутні. Мінімальною функцією є
dummy() {}
яка не виконує жодної дії і не повертає жодного значення. Такі бездіяльні функції часом корисні в якості заповнювача під час розробки програми. Якщо тип повернення опущено, припускаєтьсяint.
Програма — це лишень набір визначень змінних і функцій. Комунікація між функціями відбувається через аргументи та значення, повернуті функціями, а також через зовнішні змінні. Функції можуть знаходитись у будь-якій послідовності у вихідному тексті, а сам вихідний код програми можна розділити на численні файли за умови, що жодна функція не розділена.
Твердження return являється механізмом повернення значення викликаною функцією тому, хто її викликав. За return може слідувати будь-який вираз:
return вираз;
Вираз буде перетворено до типу повернення функції, якщо потрібно. Навколо виразу часто вживаються дужки, але вони не обов'язкові.
Викликова функція має право ігнорувати значення, повернене викликаною. Більше того, вираз після return взагалі може бути відсутній, у разі чого викликовій функцій жодного значення повернено не буде. Керування над виконанням програми також повертається викликовій без жодного значення, коли виконання «спадає з кінця» функції, досягши крайньої фігурної дужки. Це не заборонено, але ймовірно є проявом несправності, якщо функція повертає значення в одному місці, і жодного — в іншому. В будь-якому разі, якщо функції не вдалося повернути значення, то її «значення» напевне складається з непотрібу.
Наша програма пошуку зразка повертає з main статус — число знайдених співпадань. Це значення стає доступним для використання середовищем, яке викликало програму.
Механізм компіляції і завантаження програми на C, розбитої на численні файли, відрізняється в різних системах. У системі UNIX, наприклад, це завдання може виконати команда cc, згадана уРозділі 1. Припустімо, що три функції збережено у трьох різних файлах під назвою main.c,getline.c і strindex.c. В такому разі, команда
cc main.c getline.c strindex.c
скомпілює ці три файли, розміщуючи об'єктний код, отриманий в результаті, у main.o,getline.o і strindex.o, після чого завантажує їх всіх до виконавчого файла під назвоюa.out. Якщо виникла якась помилка, скажімо у main.c, цей файл можна перекомпілювати окремо, а результат завантажити з попередніми об'єктними файлами командою
cc main.c getline.o strindex.o
Команда cc користується умовними назвами «.c» напротивагу «.o» для того, щоб розрізнити вихідний файл від об'єктного.
Вправа 4-1. Напишіть функцію strindex(s,t), яка би повертала крайнє праве положення ланцюжка t у s, або -1, якщо t не знайдено.
