Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

C _Учебник_МОНУ

.pdf
Скачиваний:
199
Добавлен:
12.05.2015
Размер:
11.12 Mб
Скачать

 

 

Символи і рядки

239

 

 

 

 

Продовження табл. 7.3

 

Функція

Призначення

Формат

strcmp()

порівнює рядки і повертає нульове

int *strcmp(char *s1,

 

 

значення, якщо рядки є однакові (s1=s2),

char *s2);

 

 

від‟ємне (s1<s2) чи додатне (s1>s2).

 

 

 

 

Порівняння відбувається посимвольно і

 

 

 

 

в якості результату повертається різниця

 

 

 

 

кодів перших неоднакових символів

 

 

strncmp()

на відміну від попередньої функції,

int *strncmp

 

 

порівнює лише перші n символів рядка s1

(char *s1, char *s2,

 

 

з n символами рядка s2

size_t n);

 

 

 

 

stricmp()

порівнює два рядки, не розрізнюючи

int stricmp (char*s1,

 

 

прописні й малі літери латиниці

char *s2);

strnicmp()

порівнює лише перші n символів

int strnicmp

 

 

двох рядків, не розрізняючи великі

(char *s1, char *s2,

 

 

й малі літери латиниці

size_t maxlen);

 

 

 

 

strcpy()

копіює до s1 рядок s2, повертає s1, при

char *strcpy

 

 

цьому попереднє значення s1 втрачається

(char *s1, char *s2);

strncpy()

замінює перші n символів рядка s1

char *strncpy

 

 

на перші n символів рядка s2

(char *s1, char *s2,

 

 

size_t n);

 

 

 

strchr()

відшукує перше входження символу ch

char *strchr(char *s,

 

 

в рядок s і повертає вказівник на цей

int ch);

 

 

 

 

 

 

символ, тобто частину рядка s,

 

 

 

 

розпочинаючи з символу ch і до кінця

 

 

 

 

рядка. Якщо символу ch в рядку s немає,

 

 

 

 

результат – NULL

 

 

strrchr()

відшукує останнє входження символу

char *strrchr

 

 

в рядку і повертає частину рядка s,

(char *s, int c);

 

 

розпочинаючи з останнього входження

 

 

 

 

символу ch і до кінця рядка. Якщо символу

 

 

 

 

ch в рядку s немає, результат – NULL

 

 

strstr()

відшукує підрядок s2 в рядку s1,

char *strstr(char *s1,

 

 

повертає частину рядка s1,

char *s2);

 

 

 

 

 

 

розпочинаючи з першого спільного

 

 

 

 

символу для обох рядків і до кінця s1

 

 

strspn()

повертає довжину початкового сегмента

size_t strcspn

 

 

рядка s1, символи якого є в рядку s2

(char *s1, char *s2);

strcspn()

повертає індекс першого символу

size_t strcspn

 

 

в рядку s1, який є спільним для обох

(char *s1, char *s2);

 

 

рядків (нумерація індексів символів

 

 

 

 

розпочинається з нуля)

 

 

strset()

замінює усі символи рядка s на символ c

char *strset(char *s,

 

 

 

char c);

 

 

 

 

 

 

240

Розділ 7

 

 

 

 

 

Закінчення табл. 7.3

 

Функція

Призначення

Формат

strnset()

замінює лише перші n символів рядка s

char *strnset (char *s,

 

 

на символ c

int ch, size_t n);

 

 

 

 

strpbrk()

відшукує місце першого входження

char *strpbrk (char *s1,

 

 

у рядок s1 будь-якого символу рядка

const char *s2);

 

 

s2 і повертає частину рядка s1,

 

 

 

 

розпочинаючи з цього символу

 

 

 

 

і до кінця рядка

 

 

strrev()

реверс рядка s

char *strrev (char *s);

strtok()

повертає частину (лексему) рядка s1

char *strtok(char *s1,

 

 

від поточної позиції вказівника до

const char *s2);

 

 

розділового символу, зазначеного

 

 

 

 

у рядку s2; зазвичай використовується

 

 

 

 

для перетворювання рядка

 

 

 

 

на послідовність лексем

 

 

Розглянемо деякі з наведених у табл. 7.3 функцій детальніше на прикладах, для чого попередньо оголосимо вказівники на рядки s1, s2 та s3 і надамо їм початкові значення.

int k,n; char *s1="На Дерибасівській",*s2=" гарна погода",*s3;

n=strlen(s1);

// Обчислюється довжина рядка s1; n дорівнюватиме 17

k=strlen(s2);

// Обчислюється довжина рядка s2; k=13

k=strcmp(s1,s2);

// k=173; різниця між ASCII-кодами перших неоднакових

 

// символів рядків s1 і s2 дорівнює 173, а оскільки 173>0,

 

// можна стверджувати, що s1>s2

strcpy(s3,s2);

// s3=" гарна погода" (рядку s3 присвоюється рядок s2)

strncpy(s3,s1,2);

//Копіюються два перші символи з рядка s1 до s3

s3[2]='\0';

//Третім символом після символів"На" задається

 

// нуль-символ щоби обрізати рядок

strcat(s1,s2);

// s1="На Дерибасівській гарна погода"; до рядка s1

 

// долучається рядок s2

s3=strchr(s1,' '); // Пошук пробілів у рядку s1; тепер s3=" Дерибасівській //гарна погода" – це рядок від першого пробілу до кінця // рядка s1, тобто без першого слова

s3=strrchr(s1,' ');// Пошук останнього пробілу в рядку s1;

// тепер s3=" погода" – це останнє слово рядка s1 n=strchr(s1,' ')-s1+1;// n=3 – індекс першого пробілу в рядку s1, обчислений

// як різниця вказівників

k=strcspn(s1," ")+1;// k=3 – індекс першого пробілу в рядку s1; оскільки

// нумерація індексів символів розпочинається з 0, слід додати 1

s3=strstr(s1,s2);

// s3 = "гарна погода"; пошук рядка s2 у рядку s1

s3=strrev(s2);

// s3="адогоп анраг" – відбувається реверс рядка

s3=strupr("C++ Builder"); // s3="C++ BUILDER" – перетворення усіх

// латинських літер рядка до верхнього регістру

 

Символи і рядки

241

s3=strlwr(s3);

// s3="c++ builder" – зворотне перетворення усіх

 

 

// латинських літер рядка до нижнього регістру

 

s3=strtok(s1," "); // s3="На" – перше слово (лексема) рядка s1 до розділового

//знака, який зазначено символом (пробілом) у другому

//аргументі функції. Почергове здобуття усіх лексем

//рядка можна організовувати у циклі (див. приклад 7.5)

Отже, функції strcpy() та strncpy() призначено для копіювання рядка чи то його частини до іншого рядка. Функції strchr(), strrchr() та strstr() повертають вказівник на віднайдений символ чи підрядок.

Функція strtok() використовується для перетворювання рядка на послідовність лексем. Лексема – це послідовність символів, відокремлених символа- ми-розділювачами (зазвичай пробілами чи знаками пунктуації). Наприклад, у рядку тексту кожне слово може розглядатися як лексема, а пробіли, що відокремлюють слова одне від одного, можна розглядати як розділювачі. Для того щоб розбити рядки на лексеми, треба організувати кілька викликів функції strtok() (за умови, що рядок вміщує понад одну лексему). Більш докладно розглянемо ці функції у наведених далі прикладах програм.

Приклади програм з масивами символів

Приклад 7.2 Увести рядок до 10-ти символів і вивести через пробіл коди усіх уведених символів.

Розв‟язок. У програмі N – максимальна кількість символів для оголошення масиву, t – кількість введених символів. Функція Edit1->GetTextLen дозволяє дізнатися про кількість уведених до Edit символів. Згідно до завдання, кількість символів має не перевищувати 10-ти. Тому, якщо буде введено понад 10 символів, для обмеження кількості опрацьовуваних символів у програмі прописано команду:

if(t>10) t=10;

Звернімо увагу на те, що нумерація елементів масиву розпочинається з 0, а нумерація символів в Edit1->Text – з 1. Тому при введенні індекс символу в Edit1->Text є на 1 більше за індекс елемента масиву.

Нагадаємо ще один важливий аспект. Як було зазначено у попередньому підрозділі (див. стор. 233), друга половина кодів таблиці ASCII (яка, зазвичай, включає кирилицю), з одиничним старшим бітом, інтерпретується як від‟ємні значення, оскільки тип char за стандартом мови може мати знакову реалізацію.

Текст програми в Borland C++ Builder:

void __fastcall TForm1::Button1Click(TObject *Sender)

{const int N=10; char c[N];

int k, t=Edit1->GetTextLen(); if (t>10) t=10; Edit2->Clear();

242 Розділ 7

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

{ c[i]=Edit1->Text[i+1]; // Посимвольне введення рядка k=c[i]; // Обчислення коду символу та

Edit2->Text=Edit2->Text+IntToStr(k)+" "; // його виведення

}

}

Приклад 7.3 Увести рядок до 15 символів і замінити всі крапки на символ '_' та обчислити кількість замін.

Текст програми в Borland C++ Builder:

void __fastcall TForm1::Button1Click(TObject *Sender) { const int N=15; char c[N];

int i,k=0,t=Edit1->GetTextLen(); if (t>N) t=N;

Edit2->Clear(); for (i=0; i<t; i++)

{ c[i]=Edit1->Text[i+1]; if(c[i]=='.')

{c[i]='_'; k++;}

}

Edit3->Text=IntToStr(k);

for (i=0; i<t; i++) Edit2->Text=Edit2->Text+c[i];

}

Приклад 7.4 Створити рядок з усіх великих літер англійської абетки.

Розв‟язок. Оскільки тип char є порядковим типом, то його можна застосовувати у якості типу параметра циклу. Після застосування операції інкремента (++) змінна типу char набуде значення коду наступного символу.

Текст програми в консолі:

#include <vcl.h> #pragma hdrstop #include <iostream.h>

//------------------------------------------------------------

#pragma argsused

int main(int argc, char* argv[])

{ char s[27]; // 26 латинських літер i '\0' char c; int i=0;

for(c = 'A'; c <= 'Z'; c++) s[i++] = c;

s[i] = '\0'; // Записування символу '\0' до останнього символу рядка cout << "Англійська абетка: " << s;

cin.get(); return 0;

}

Результат виконання програми:

Англійська абетка: ABCDEFGHIJKLMNOPQRSTUVWXYZ

Символи і рядки

243

Приклад 7.5 Увести рядок і вивести всі його слова окремо без розділових знаків.

Розв‟язок. Наведемо три способи розв‟язання цього завдання за допомогою функцій strtok() та strncpy(). Усі варіанти розв‟язання є працездатними як у консолі, так і для C++ Builder.

П е р ш и й с п о с і б

Для розбивання рядка на слова (лексеми) застосовуватимемо функцію strtok(), яка має два аргументи: рядок, який треба розбити на лексеми, і рядок, який містить символи-розділювачі.

Перший виклик функції strtok у програмі t = strtok(s, " .,;?!-");

присвоїть змінній t вказівник на перше слово рядка s. Другий аргумент наведеної функції містить можливі розділові символи. Функція strtok() відшукує перший символ у рядку s, який не є розділювачем. Це є початок першого слова. Потім функція віднаходить розділювач у рядку і замінює його на нуль-символ ('\0'). Цим завершується поточне слово. Функція strtok() зберігає вказівник на наступний символ рядка s за даним словом і повертає вказівник на поточну лексему (слово). У наступних викликах strtok() у програмі для почергового виокремлення слів з рядка s першим аргументом функції зазначається NULL, для того, щоб виокремлення наступного слова рядка s відбувалося з позиції, яку було збережено попереднім викликом strtok(). Якщо лексем при виклику strtok() більше немає, strtok() повертає NULL – і відбувається вихід із циклу.

Зверніть увагу, що strtok() модифікує вхідний рядок; тому, якщо рядок після виклику strtok() знову використовуватиметься у програмі, треба завчасно зробити копію рядка.

Цей алгоритм можна застосовувати для виокремлення чисел, але тоді у якості розділових знаків не слід застосовувати крапку, яка може інтерпретуватися як десяткова крапка.

Текст програми у консолі:

#include <iostream.h>

#include <string.h> int main ()

{char s[80], *t;

puts(" Введіть рядок, який треба розбити на лексеми:"); gets(s);

puts("\n Лексеми: "); t=strtok(s, " .,;?!-"); while (t != NULL)

{ puts(t);

t = strtok(NULL, " .,;?!-");

}

cin.get(); return 0;

}

// Допоки у рядку є пробіли,

244

Розділ 7

Результат виконання програми:

Введіть рядок, який треба розбити на лексеми:

Hi, Tony! How are you? – I’m OK, thanks.

Лексеми:

Hi

Tony

How are you

I’m

OK thanks

Д р у г и й с п о с і б

Для виокремлення слів рядка вважатимемо за ознаку завершення слова пробіл. Оскільки після останнього слова рядка здебільшого пробіл є відсутній, тому долучаємо його до рядка s у заздалегідь зарезервоване місце.

Рухаючись рядком, почергово виокремлюємо частину рядка s у змінну slovo. Виокремлення слова можна реалізувати за допомогою функції strtok() чи то, як у нижченаведеному тексті програми, функції strncpy(). Ця функція копіює частину рядка s, розпочинаючи з поточної

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

Після опрацювання усього рядка, щоб звільнити пам‟ять, яку біло виділено за допомогою new, треба перемістити вказівник на початок рядка: s-=n, де n – кількість літер у рядку.

Текст програми в C++ Build er:

void __fastcall TForm1::Button1Click(TObject *Sender) {int i, n=Edit1->Text.Length();

char *s=new char[n+2], *slovo=new char[n+1]; strcpy(s, Edit1->Text.c_str());

strcat(s, " "); n=strlen(s); Memo1->Clear(); while(strchr(s,' '))

{for(i=0; i<n+2 && s[i]!=' '; i++); //відшукується позиція пробілу і strncpy(slovo, s, i); //копіюються символи до пробілу у змінну slovo slovo[i]='\0';

Memo1->Lines->Add(AnsiString(slovo));

s+=i+1;

// Перехід до наступного слова

}

 

s-=n;

// Повернення на початок рядка

delete[]s;

delete[]slovo;

}

 

Символи і рядки

245

Т р е т і й с п о с і б

Іноді при виокремленні слів рядка виникає потреба у зберіганні цих слів в однотипному масиві для їхнього подальшого опрацювання. Для виділення пам‟яті для масиву arr вказівників на слова спочатку слід визначити кількість слів (kol). Зверніть увагу, що в програмі ознака завершення слова визначається як: і-й символ не є пробілом (!isspace(s[i])), а (і+1)-й символ – пробіл

(isspace(s[i+1])).

Текст програми в C++ Builder:

void __fastcall TForm1::Button1Click(TObject *Sender) {int n=Edit1->Text.Length(), i, j=0, kol=0;

char *s=new char[n+2]; char *slovo=new char[n+1];

strcpy(s, Edit1->Text.c_str()); strcat(s," ");

n=strlen(s);

for(i=0;i<n-1;i++) if(!isspace(s[i])&&isspace(s[i+1])) kol++; char * *arr=new char *[kol];

Memo1->Clear(); while(strchr(s,' '))

{for(i=0; i<n+2 && s[i]!=' '; i++); strncpy(slovo, s, i); slovo[i]='\0';

arr[j]=new char[strlen(slovo)+1]; strcpy(arr[j], slovo);

j++;

s+=i+1;

}

s-=n;

for(i=0; i<kol; i++) Memo1->Lines->Add(AnsiString(arr[i])); for(i=0; i<kol; i++) delete []arr[i];

delete[]s;

delete[]slovo;

delete[]arr;

}

Приклад 7.6 Вивести індекси всіх входжень літери 'a' до рядка.

Розв‟язок. Для виконання завдання доцільно використати функцію strchr(), яка відшукує перше входження відповідного символу до рядка і повертає вказівник на цей символ, тобто частину рядка s, розпочинаючи з цього символу і до кінця рядка. Якщо символу, зазначеного другим аргументом функції, в рядку немає, результатом функції є NULL.

У разі відсутності символу 'a' у рядку s передбачено логічну змінну F, яка ще за першої перевірки щодо наявності символу сигналізує про його можливу відсутність, після чого виводиться відповідне повідомлення і відбувається вихід з програми.

246

Розділ 7

Текст програми у консолі:

#include <iostream.h>

#include <string.h> int main ()

{char s[80], *p; bool F=0;

puts("Введіть рядок:"); gets(s);

printf("Відшукуємо літеру 'a' у рядку \"%s\"...\n",s); p=strchr(s,'a');

if(p==NULL)

{puts("not found!"); return 0;

}

while(p!=0)

{printf ("found at %d\n",p-s+1); p=strchr(p+1,'a');

}

cin.get(); return 0;

}

Результат виконання програми:

Введіть рядок:

I am happy!

Відшукуємо літеру 'a' у рядку "I am happy! "...

found at 3 found at 7

Введіть рядок: I’m hungry!

Відшукуємо літеру 'a' у рядку "I’m hungry! "...

not found!

Приклад 7.7 Увести рядок і перевірити, чи є він символьним поданням цілого числа.

Розв‟язок. Перевірку, чи є символ цифрою, можна здійснити чи то за допомогою функції isdigit(), чи за перевірки належності його до діапазону цифр.

Текст програми у консолі:

#include <stdio.h> void main()

{char st[20];

printf("Введіть ціле число "); scanf("%s",&st);

int i, n=strlen(st);

Символи і рядки

247

// Перший символ може бути цифрою чи знаком '-' if((st[0]<'0'||st[0]>'9')&&st[0]!='-')

{printf("Рядок не є цілим числом"); cin.get();

return 0;

}

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

if(st[i]<'0' || st[i]>'9') // Решта символів має бути цифрами

{printf("Рядок не є цілим числом"); cin.get();

return 0;

}

printf("Рядок є цілим числом.\n"); cin.get();

return 0;

}

Результати виконання програми:

Введіть ціле число 23.5 Введений рядок не є цілим числом.

Введіть ціле число -56 Введений рядок є цілим числом.

Приклад 7.8 Увести рядок і перевірити, чи є він дійсним числом. Текст програми у консолі:

#include <stdio.h> #include <conio.h> void main()

{char st[20];

int err=0; //Спочатку вважаємо, що рядок не є дійсним числом printf("Введіть дійсне число ");

scanf ("%s",&st);

int i, k=0, n=strlen(st); if(!isdigit(st[0])&&st[0]!='-')err=1;//Перший символ – цифра чи '-'? for(i=1; i<n-1; i++)

{if(!isdigit(st[i]) && st[i]!='.')//Якщо символ не є цифрою чи

{err=1; break;}//десятковою крапкою, переривається перевірка решти if(isdigit(st[i-1])&&st[i]=='.' && isdigit(st[i+1])) {k++; //Якщо символ є десятковою крапкою, а попередній і наступний

if(k>1) // символи – цифри, перевіряється можливість повторів таких {err=1; break;}//ситуацій і, якщо '.' вже була, перевірка припиняється

}

}

if(k==0)err=1; // Десяткових крапок усередині цифр не було? if(err==1) printf("Число не є дійсним!");

else printf("Число є дійсним!"); cin.get(); return 0;

}

248

Розділ 7

Приклад 7.9 Створити програму для введення рядка і можливості вилучення із заданої позиції певної кількості символів рядка. Значення кількості символів для вилучення й номера позиції ввести з клавіатури.

Розв‟язок. Цей алгоритм є поширеним у застосуванні і розв‟язувати його можна по-різному, приміром за допомогою допоміжного рядка і вибирання до нього символів початкового рядка без тих символів, які треба “вилучити”, після чого слід перезаписати створений рядок до початкового. Наведений нижче алгоритм вилучення частини рядка є більш зручним, оскільки не потребує використання допоміжного рядка. Розглянемо цей алгоритм на прикладі рядка s:

char *s="Погода дуже тепла";

У розглянутому нижче прикладі ціла змінна pos є номером символу, з позиції якого слід розпочати вилучення, kol – кількість символів, що їх буде вилучено, &s[pos] – частина рядка s, розпочинаючи з символу з індексом pos, а pos+kol – індекс першого символу, який не буде вилучено. Якщо pos=7 і kol=5, команда

strcpy(&s[pos], &s[pos+kol]);

переставить (скопіює) слово “тепла” з нуль-символом на місце слова “дуже” унаслідок присвоювання вказівників. При цьому перша частина рядка залишиться на місці. Отже, слово “дуже” з пробілом зникне (його буде вилучено), а рядок стане коротшим.

 

&s[pos]

&s[pos+kol]

S

 

 

 

 

 

 

 

П о г

о д а

 

д у ж е

 

т е п л а \0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

0

1

2 3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

П

о

г

о

д

а

 

т

е

п

л

а

\0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Текст програми у консолі:

#include <iostream.h> void main()

{int pos, kol;

char *s=new char[80]; gets(s);

cout<<"pos = "; cin>>p; cout<<"kol= "; cin>>kol;

pos --; //Коригування номера, оскільки нумерація символів розпочинається з 0 if(!(&s[pos+kol]==NULL || &s[pos]==NULL || pos<0 || kol<0))

strcpy(&s[pos], &s[pos+kol]); puts(s);

cin.get(); return 0;

}

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