Для початку, сплануймо та напишемо програму виводу кожного рядка вводу, який містить певний «зразок» або ланцюжок знаків. (Своєрідну імітацію програми 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 не знайдено.