Смекни!
smekni.com

Мова програмування С++ (стр. 6 из 7)

strcat(s,” “);// додаємо пробіл після слова

}

cout<<”&bsol;nНовий рядок:&bsol;n”<< s;// виводимо результат

}

Приклад 2:

Програма яка підраховує скільки разів задане слово зустрічається у тексті файлу. Наприклад, у англійській поговірці “Don’t trouble trouble until trouble troubles you” слово “trouble” у чистому вигляді зустрічається 3 рази.

#include <fstream.h>

#include <string.h>

# include<ctype.h>

void main()

{const int len=81;

char word[len], line [len];// масиви для слова і рядка

cout<< “Введiть слово для пошуку:”; cin>> word;

int_lword=strlen(word);// визначення довжини слова

ifstream fin (“text.txt”, ios:: in | ios:: nocreate);

if(!fin) {cout<< “Помилка відкриття файлу.”<<endl;return 1;}

int count=0;

// поки не досягнуто нуль-символу

while(fin.getline(line, len))

{char *p=line;// вказівникові присвоєно адресу рядка

while(p=strstr(p,word))/* якщо слово знайдено

вказівник стає на позицію

початку слова у рядку*/

{ // адреса початку входження слова передається с

char * c=p;

p+=l_word;// перехід вказівника р через слово

// слово не на початку рядка

if(c!=line)

/* Чи є символ перед словом розділювачем? Інакше –

перейти до наступної ітерації */

if(!ispunct(*(c-2))&& isspace(*(c-1))) continue;

// Чи є символ після слова розділювачем?

if (ispunct(*p)|| isspace(*p)|| (*p==’&bsol;0’)) count ++;

}

}

cout << “Слово зустрічається в тексті ”<< count;

<<” разів”<<endl;

}


9. Функції користувача

9.1 ФУНКЦІЇ: ВИЗНАЧЕННЯ, ОПИС, ВИКЛИК

Функцію в С++ можна розглядати:

· як один з похідних типів даних (поряд з масивами і вказівниками);

· як мінімальний виконуваний модуль програми (підпрограму).

Всі функції мають однаковий формат визначення:

<тип><ім’я_функції>(<список_формальних_параметрів>)

<тіло_функції>,

де <тип> - тип результату, який повертається функцією; в разі, якщо функція не повертає ніякого значення, її специфікують типом void і називають “порожньою”. Найчастіше, це функції, які виводять на екран повідомлення чи виконують деякі зміни параметрів, проте не можуть передати певний результат іншим змінним при виклику.

<ім’я_функції> - або main для головної функції, або довільний ідентифікатор;

<список_формальних_параметрів> - або порожній ( ), або список, кожен елемент якого записується як:

<тип> <ім’я_формального_параметру>

Наприклад:

(int k )

(char i, char j, int z)

<тіло_функції> - це набір операторів, що виконуються у фігурних дужках {} при виклику функції. Тіло функції може бути складовим оператором або блоком. Визначення функцій не можуть бути вкладеними.

Для передачі результату з функції у функцію, що її викликала, використовується оператор return. Його можна використовувати у двох формах:

1) return 0; - завершує функцію, яка не повертає ніякого значення (тобто перед її іменем вказано тип void);

2) return <вираз>; - повертає значення виразу, тип виразу повинен співпадати з типом функції.

Приклад 1:

int op (char c, int x, int y)

{switch (c)

{case ‘+’ : return x+y;

case ‘-’ : return x-y;

case ‘*’ : return x*y;

case ‘/’ : return x/y;

default: cout<<“&bsol;nОперація не визначена!”;

return 0;

}

}

Приклад 2.

float cube(float d)

{return d*d*d;}

Після визначення функцію можна багаторазово використовувати у програмі для виконання однотипних дій над різними змінними.

Виклик функції має наступний вигляд:

<ім’я_функції>(<список фактичних параметрів>);

<список фактичних параметрів - або сигнатура, є переліком виразів, кількість яких дорівнює кількості формальних параметрів функції. Між формальними і фактичними параметрами повинна бути відповідність за типами. В якості фактичних параметрів можна використовувати змінні, визначені та ініціалізовані у програмі, з типами, що відповідають типам формальних параметрів. Якщо функція повертає значення, її виклик можна використати у правій частині операції присвоювання з метою передачі результату функції змінній, тип якої співпадає з типом функції, що викликається.

Наприклад:,

void main(){float s, f=0.55; s=cube(f);…}

В якості фактичних параметрів також можуть виступати явно задані константні значення:

Наприклад, виклик функції з прикладу 1 має наступний вигляд:

c = op ( ‘+’, 5 ,4 );

Оскільки визначення функцій не можуть міститися всередині блоків та складових операторів, тобто в інших функціях, у програмі вони можуть розміщуватися як до, так і після функції, яка їх викликає. В останньому випадку перед використанням функції у програмі необхідно розмістити її опис, або прототип, інакше виникатимуть проблеми. Компілятор передусім послідовно перевіряє коректність виклику та використання об¢єктів у програмі, при виявленні функції, яка не була описана чи визначена раніше, видасть повідомлення про помилку і вказівку про те, що функція повинна містити прототип. Те саме повідомлення Ви побачите на екрані, якщо використаєте у програмі функцію зі стандартних бібліотек і не під¢єднаєте заголовний файл, у якому вона описана. Прототип функції користувача багато в чому нагадує заголовок функції і має наступний формат:

<тип><ім’я_функції>(<список_формальних_параметрів>);

Головною відмінністю є наявність в кінці опису крапки з комою.

Так, прототипи функцій з прикладів 1 та 2 матимуть вигляд:

cube(float);

op(char c, int, int);

Прототип надає компіляторові інформацію про тип та ім¢я функції, а також про типи, кількість та порядок розміщення параметрів, які їй можна передавати. Зважаючи на це, імена формальних параметрів зазначати необов¢язково. Прототип являє собою зразок для здійснення синтаксичної перевірки компілятором.

9.2 ПЕРЕДАЧА МАСИВІВ У ФУНКЦІЮ

Якщо в якості параметру функції використовується позначення масиву, необхідно передати до функції його розмірність.

Приклад 3: Обчислення суми елементів масиву

int sum (int n, int a[] )

{ int i, s=0;

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

s+=a[i];

return s;

}

void main()

{ int a[]={ 3, 5, 7, 9, 11, 13, 15 };

int s = sum( 7, a );

cout<<s;

}

Рядки в якості фактичних параметрів можуть визначатися або як одновимірні масиви типу char[], або як вказівники типу char*. На відміну від звичайних масивів, для рядків немає необхідності явно вказувати довжину рядка, оскільки будь-який рядок обмежується нуль-символом.

При передачі у функцію двовимірного масиву в якості параметру так само необхідно задавати кінцеві розміри масиву у заголовку функції. Робити це можна:

а) явним чином (а[3][4] тоді функція працюватиме з масивами лише заданої розмірності);

б) можна спробувати для квадратної матриці через додатковий параметр ввести розмірність (void matrix(double x[][], int n)), де n – порядок квадратної матриці, а double x[][] – спроба визначення двовимірного масиву зі заздалегідь невизначеними розмірами. В результаті на таку спробу компілятор відповість: Error…: Size of type is unknown or zero;

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

Приклад 4.

# include<iostream.h>

//Функція транспонування квадратної матриці

void trans (int n, double*p[])

{double x;

for (int i=0; i<n-1; i++)

for(int j=i+1; j<n; j++)

{x=p[i][j];

p[i][j]=p[j][i];

p[j][i]=x;

}

}

void main(){

// Задано масив для транспонування

double A[4][4]={11, 12, 13, 14

21, 22, 23, 24

31, 32, 33, 34

41, 42, 43, 44};

// Допоміжний двовимірний масив вказівників

double * ptr[]={(double*)&A[0], (double*)&A[1],

(double*)&A[2], (double*)&A[3]};

// Виклик функції

int n=4;

trans(n, ptr);

for(int i=0; i<n;i++)

{cout<<”&bsol;n Рядок ”<<(i+1)<<”:”;

for(int j=0; j<n; j++)

cout<<”&bsol;t”<< A[i][j];

}

}

9.3 ПЕРЕВАНТАЖЕННЯ ФУНКЦІЙ У С++

Перевантаження полягає в тому, що функція з одним іменем по різному виконується і повертає значення різних типів при передачі до неї фактичних параметрів у різній кількості та з різними типами. Для забезпечення перевантаження функцій необхідно для одного імені функції визначити заголовок і набір операторів для всіх функцій, що пов’язані з ним.

Приклад 5:

#include <iostream.h>

int max_element ( int n, int a[])

// знаходить максимальний елемент для масиву типу int

{

int max=a[0];

for ( i=1; i<n; i++)

if (a[i]>max) max=a[i];

return max;

}

long max_element ( int n, long a[])

// знаходить максимальний елемент для масиву типу long

{

long max=a[0];

for ( i=1; i<n; i++)

if (a[i]>max) max=a[i];

return max;

}

double max_element ( int n, double a[])

// знаходить максимальний елемент для масиву типу double

{

double max=a[0];

for ( i=1; i<n; i++)

if (a[i]>max) max=a[i];

return max;

}

float max_element ( int n, float a[])

// знаходить максимальний елемент для масиву типу float

{

float max=a[0];

for ( i=1; i<n; i++)

if (a[i]>max) max=a[i];

return max;

}

void main ( )

{

int x[]={10, 20, 30, 40, 50, 60};

long y[]={12L, 44L, 22L, 37L,30L};

int m1=max_element(6, x );

long m2=max_element(5, y);

}

9.4 ФУНКЦІЇ ЗІ ЗМІННОЮ КІЛЬКІСТЮ ПАРАМЕТРІВ

У мовах С та С++ допускаються функції, кількість параметрів у яких при компіляції не визначена. Крім того, можуть бути невідомими і типи параметрів. Кількість і типи параметрів стають відомими лише в момент виклику функції, коли явно задається список фактичних параметрів. Формат заголовку функції зі змінним переліком параметрів має вигляд:

<тип> <ім’я> (<специфікація_формальних_параметрів, …>)

Проте, кожна функція зі змінним переліком параметрів повинна мати механізм визначення їх кількості або типу. Для цього використовують два основні підходи:

1) Передача у функцію значення реальної кількості фактичних параметрів за допомогою одного або декількох обов’язкових параметрів;

2) Додавання до списку фактичних параметрів спеціального параметру-індикатора з унікальним значенням, яке буде сигналізувати про кінець списку.

Підхід (1) демонструє програма у прикладі 6, яка містить функцію зі змінним списком параметрів, перший з яких визначає кількість фактичних параметрів, що використовуються при викликанні функції: