Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
knrc (1).pdf
Скачиваний:
12
Добавлен:
12.02.2016
Размер:
925.69 Кб
Скачать

22

РОЗДIЛ 1. ВСТУПНИЙ УРОК

Одне, i тiльки одне, з двох тверджень, пов’язаних з if-else, буде виконано. Якщо вираз в дужках є iстинним, буде виконано твердження1, якщо нi — твердження2. Твердження можуть бути як одним, так i багатьма, включеними у фiгурнi дужки. У програмi пiдрахунку слiв, пiсля else знаходиться if з двома твердженнями, включеними у фiгурнi дужки.

Вправа 1-11. Як би ви перевiрили програму пiдрахунку слiв? Якi типи вводу ймовiрно виявлять помилки, якщо такi є?

Вправа 1-12. Напишiть програму, яка би виводила свiй ввiд по одному слову на рядок.

1.6Масиви

Тепер напишiмо програму, яка пiдрахує кiлькiсть кожної цифри, пропускiв (пробiл, табуляцiя i знак нового рядка) i решти знакiв. Це трохи штучно, але дозволяє проiлюструвати декiлька аспектiв C в однiй програмi.

У нас є дванадцять категорiй можливого вводу, тож має змiст використати масив для утримування числа повторень тiєї самої цифри, замiсть десяти окремих змiнних. Ось одна з можливих версiй програми:

#include <stdio.h>

/* лiчить цифри, пропуски та iншi знаки */ main()

{

int c, i, nwhite, nother; int ndigit[10];

nwhite

= nother

= 0;

for (i

= 0; i <

10; ++i)

ndigit[i] =

0;

while ((c = getchar()) != EOF) if (c >= ’0’ && c <= ’9’)

++ndigit[c-’0’];

else if (c == ’ ’ || c == ’\n’ || c == ’\t’) ++nwhite;

else ++nother;

printf("digits =");

for (i = 0; i < 10; ++i) printf(" %d", ndigit[i]);

printf(", white space = %d, other = %d\n", nwhite, nother);

1.6. МАСИВИ

23

}

Вивiд самої програми може виглядати як

digits = 9 3 0 0 0 0 0 0 0 1, white space = 123, other = 345

Оголошення

int ndigit[10];

описує ndigit, як масив з 10-и цiлих. Iндексацiя масивiв завжди починається з нуля в C, тож елементами будуть ndigit[0], ndigit[1], . . . , ndigit[9]. Це вiдображено у циклах for, якi iнiцiалiзують i виводять масив.

Iндексом може бути будь-який вираз типу int, включаючи цiлочисельну змiнну, як от i, та цiлочисельнi константи.

Ця програма покладається на символьне представлення цифр. Так, наприклад, перевiрка

if (c >= ’0’ && c <= ’9’)

визначає, чи символ, який мiститься в c є цифрою. Якщо так, числовим значенням цiєї цифри є

c - ’0’

Це працює тiльки за умови, що символи ’0’, ’1’, . . . , ’9’ мають послiдовнозростаючi значення. На щастя, це справджується в усiх наборах символiв.

За означенням, char — це просто малi цiлi, тож змiннi i сталi типу char тотожнi int в арифметичних виразах. Це природньо та зручно; наприклад, c - ’0’ є цiлочисельним виразом зi значенням мiж 0 i 9, що вiдповiдають знакам вiд ’0’ до ’9’, збереженим у c, тож чинним iндексом масиву ndigit.

Рiшення того, чи знак є цифрою, пропуском, чи чимось iншим здiйснюється послiдовнiстю

if (c >= ’0’ && c <= ’9’) ++ndigit[c-’0’];

else if (c == ’ ’ || c == ’\n’ || c == ’\t’) ++nwhite;

else ++nother;

24

РОЗДIЛ 1. ВСТУПНИЙ УРОК

Конструкцiя

if (умова1) твердження1

else if (умова2) твердження2

...

...

else твердження

зустрiчається доволi часто в програмах, як один з способiв виразити розгалуження рiшень. Умови розглянуто по-порядку, починаючи зверху, до тих пiр, доки одна з умов не справдиться, у разi чого буде виконано вiдповiдне твердження, i цiла конструкцiя закiнчить своє iснування. Якщо жодна з умов не є iстинною, тодi буде виконано твердження пiсля останнього else, якщо таке iснує. Якщо ж останнє else i вiдповiдне твердження вiдсутнi, як у випадку з програмою вiдлiку слiв, тодi жодної дiї не вiдбудеться. Можна використати будь-яку кiлькiсть

else if (умова) твердження

-груп, мiж початковим if i кiнцевим else.

Щодо стилю, то радимо форматувати цю конструкцiю саме так, як ми показали; якби кожний if вирiвнювався з попереднiм else, довга черга розгалужень змiстилась би до правого боку сторiнки.

Твердження switch, яке буде розглянуто у Роздiлi 4, — це iнший спосiб написання розгалуження рiшень, особливо корисне у випадку, коли умова складається з якогось цiлого чи символьного виразу, який порiвнюється з набором констант. Для контрасту, у Роздiлi 3.4 ми представимо switch-версiю цiєї програми.

Вправа 1-13. Напишiть програму, яка би виводила гiстограму довжин слiв вводу. Гiстограму легко намалювати горизонтальними стрижнями; вертикальну орiєнтацiю гiстограми втiлити трохи складнiше.

Вправа 1-14. Напишiть програму виводу гiстограми частоти рiзних знакiв вводу.

1.7Функцiї

У C, функцiя — це еквiвалент пiдпрограм чи функцiй Fortran, або процедур чи функцiй Pascal. Функцiї забезпечують зручним способом герметизувати, або вiдокремити, якесь обчислення, яке пiсля того можна використати не хвилюючись про те, як саме воно було втiлене. Iз добре спроектованими функцiями, можна не звертати уваги, як

1.7. ФУНКЦIЇ

25

саме вирiшено проблему; знання того, що саме зроблено — вистачить. C робить використання функцiй легким, зручним i ефективним; ви часто побачите короткi функцiї, означенi та викликанi тiльки один раз лише тому, що вони прояснюють якийсь кусочок коду.

Досi ми використовували тiльки такi функцiї як printf, getchar i putchar, якi нам було надано; тепер час написати декiлька власних. Оскiльки C не має експоненцiйного оператора **, як у Fortran, дозвольте нам продемонструвати механiку визначення функцiї шляхом написання власної power(m,n), яка зводить цiле m до додатнього чiлочисельного степеню n. Тобто, значенням power(2,5) буде 32. Ця функцiя не є практичною рутиною зведення до степеню, оскiльки вона оперує лише додатними показниками степеня з невеликими значеннями, але вона пiдходить для iлюстрацiї. (Стандартна бiблiотека мiстить функцiю pow(x,y), яка обчислює x .)

Наступне — це функцiя power разом iз main для її виклику, тож ви можете побачити всю структуру зразу.

#include <stdio.h>

int power(int m, int n);

/* випробовування функцiї power */ main()

{

int i;

for (i = 0; i < 10; ++i)

printf("%d %d %d\n", i, power(2,i), power(-3,i)); return 0;

}

/* power: зводить base до n-ного степеня; n >= 0 */ int power(int base, int n)

{

int i, p;

p = 1;

for (i = 1; i <= n; ++i) p = p * base;

return p;

}

Визначення функцiї має таку форму:

тип_повернення назва_функцiї(оголошення параметрiв, якщо є)

26

РОЗДIЛ 1. ВСТУПНИЙ УРОК

{

оголошення

твердження

}

Визначення функцiй можуть з’являтися в будь-якiй послiдовностi, в одному вихiдному файлi або в багатьох, за умови, що функцiю не розщеплено по рiзних файлах. Якщо вихiдний текст програми розбито на декiлька файлiв, вам, можливо, доведеться здiйснити додатковi дiї, щоб скомпiлювати та завантажити її, нiж коли все знаходиться в одному, але це залежить вiд операцiйної системи, а не властивостей мови. Наразi, ми припустимо, що обидвi функцiї знаходяться у тому самому файлi, тож все, чого ви навчилися про запуск C-програм, працюватиме. Функцiю power викликано двiчi всерединi main у рядковi

printf("%d %d %d\n", i, power(2,i), power(-3,i));

Кожний виклик передає два аргументи функцiї power, яка, в свою чергу, повертає цiле для форматування i виводу. Всерединi виразу power(2,i) є цiлим, так само як 2 та i. (Не всi функцiї видають цiле значення; ми розглянемо це питання у Роздiлi 4.)

Перший рядок самої power

int power(int base, int n)

оголошує типи параметрiв та їхнi назви, i тип результату, який функцiя повертає. Назви, використанi power для свої параметрiв, є локальними для power, i не видимi для будь-якої iншої функцiї — iншi функцiї можуть скористатися з тих самих назв, не викликаючи конфлiктiв. Те саме стосується змiнних i та p — змiнна i з power не має жодного стосунку до i з main.

Ми, загалом, користуватимемося словом параметр для назв змiнних функцiї зi списку в круглих дужках. Термiни формальний аргумент i дiйсний аргумент також iнодi використовуються для такого розрiзнення.

Значення, обчислене power, передається main за допомогою твердження return. Будь-який вираз може слiдувати за return:

return вираз;

Функцiї не обов’язково мають повертати якесь значення; твердження return без якогось виразу передає контроль, але жодного корисного значення, викликачевi, так само як падiння з кiнця функцiї, коли досягнуто кiнцевої фiгурної дужки. Викликова функцiя також може проiгнорувати значення, повернене викликаною.

1.7. ФУНКЦIЇ

27

Ви, можливо, помiтили return укiнцi main. Оскiльки main — це така сама функцiя, як i будь-яка iнша, вона також може повертати значення викликачевi, що насправдi є середовищем у якому запущено програму. Типово, повернення нуля означає нормальне завершення; ненульовi значення сигналiзують незвичайнi або помилковi умови завершення. Дотепер, ми, для спрощення, опускали твердження return всерединi main, але надалi ми включатимемо його, як нагадування, що програми мають повертати середовищу свiй статус.

Оголошення

int power(int base, int n);

перед самою main вказує на те, що power — це функцiя, що очiкує два аргументи типу int i повертає один int. Це оголошення, яке називається прототипом функцiї, має збiгатися з визначенням i використанням power. Це спричинить помилку, якщо визначення функцiї або якийсь випадок її використання не зiйдеться з прототипом.

Назви параметрiв не мусять збiгатися. Насправдi, назви параметрiв не обов’язковi в прототипi функцiї, тож його можна написати як

int power(int, int);

Вдало вибранi iмена змiнних — це хороша пiдказка, однак, тож ми часто їх використовуватимемо. Iсторична примiтка: найбiльшою змiною мiж ANSI C i раннiми версiями є спосiб в який функцiї оголошено i означено. В оригiнальнiй версiї C, функцiю power було би написано так:

/* power: зводить base до n-ного степеня; n >= 0 (старий стиль) */ power(base, n)

int base, n;

{

int i, p;

p = 1;

for (i = 1; i <= n; ++i) p = p * base;

return p;

}

Параметри вказано всерединi круглих дужок, а їхнi типи — перед вiдкриттям фiгурних; неоголошенi параметри вважаються за int. (Корпус функцiї такий самий як i у попередньому прикладi.)

Оголошення power на початку програми виглядало би так:

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]