Ефективність мови С++ багато в чому визначається
наявністю в ній розвинутих засобів для обробки символьної інформації. У
стандартній бібліотеці С++ передбачено багато функцій, що виконують прості дії
з символьними даними. Тому ця мова найкраще підходить для системної роботи:
написання компіляторів, інтерпретаторів, операційних систем, редакторів тексту
тощо.
У мові С та в ранніх версіях мови С++ рядки розглядалися
як символьні масиви, і вся робота з ними ґрунтувалася на використанні цих
масивів. Розроблена бібліотека функцій string.h містить потужні засоби для
роботи з рядковими масивами. Рядок являє собою масив символів, який
закінчується нуль−символом. Нагадаємо, що нуль−символ має код, що
дорівнює 0,
і запис у вигляді керуючої послідовності ‘\0’.
За розташуванням нуль−символа визначається фактична довжина рядка. Кількість
елементів символьного масиву складається з кількості символів у рядку плюс 1, тому що
нуль−символ також є елементом масиву.
Для опису рядка використовуються звичайні засоби опису
масивів, наприклад: char
str[25];. Індексування такого масиву, як і будь−якого
іншого, починається з нуля.
Символьні послідовності, розділені тільки пропусками, розглядаються
як один рядок.
Адреса першого символа рядка може використовуватися
по− різному:
− якщо рядок застосовується при ініціюванні масиву
типу char, адреса його першого елемента стає синонімом імені масиву.
Наприклад, ідентичними є такі описи масиву:
char
st [ ] = “Слово”;
char st [6] = “Слово”;
char st [6] = {‘С’ ‘л’ ‘о’ ‘в’ ‘о’
‘\0’};
− якщо рядок використовується для ініціювання
покажчика типу char*,
адресапершого символа рядка буде початковим значенням покажчика, наприклад:
char *pst = “Слово”;.
Тут описується змінна−покажчик pst, яка одержує
початкове значення, що дорівнює адресі першого елемента (символа ‘С‘);
якщо рядок використовується у виразі, що застосовує
покажчик, то компілятор підставляє у вираз рядка адресу його першого символа.
Слід звернути увагу на те, що при описі символьного
масиву його ім’я — не змінна, а покажчик−константа на початок рядка, тому
її не можна використовувати в деяких операціях адресної арифметики. Зокрема, не
можна здійснювати операцію присвоювання вигляду:
char
st [20];
st =
“Петренко”; — запис неправильний, тому що
не можна змінити значення st.
Виконання дій з елементами символьного масиву
здійснюється через індекси або через покажчики. Для доступу до будь−
якого символа рядка використовується індекс масиву char. Тобто, якщо
описана змінна char str
[3];, то третім елементом масиву можна скористатися,
записавши: str [2] або
*(str+2).
У процесі роботи з елементами двовимірного
масиву застосовують або індекси масиву, або
індекси покажчиків. Якщо описаний список прізвищ char spis [5] [15];,
то для використання символа масиву слід записати: spis [і][j] або *(spis [і] + j).
Аналогічно, якщо оголошений масив покажчиків char *str [5], що
містить 5 елементів, кожний з яких вказує на рядок, то доступ до символа рядка
можна здійснити з використанням запису *(str
[і] + j).
Введення рядків можна здійснювати різними способами,
найбільш розповсюдженими з яких є:
char st 15] = “Диск”;
char st [ ] =
“Диск”;
char *pst = “Диск”;.
У цьому випадку двовимірні масиви можна ініціювати по−різному, наприклад, у вигяді:
char str [5][20] = {“Петренко И. И. “Головко С. С.
“, . . . ,};
char str [ ][20] = {“Петренко И. И. “, “Головко С. С.
. . . ,};
char *pst[5] = {“Петренко И. И. “, “Головко С. С.
“, . . . ,};
char *pst[ ] = {“Петренко И. И. “, “Головко С. С.
“…….., };
char st [5]; сіn >> st;
char *pst; сіn >> *pst;
char str [5][20]; сіn >> str [i];
char *pst [5]; cin >> *(pst
[i]);
get (st[i]);
cin.get
(str[i], size, endl);,
де size — кількість
символів, що читаються;
cin.getline
(str[i], sizeof (str[i]−l));,
де sizeof() — функція
визначення розміру рядка.
Виведення рядкових даних реалізується з використанням
стандартного вихідного потоку cout:
cout << st;
cout.write(st, size); тощо.
Для потокового введення−виведення доцільно застосовувати функції setw(w),setprecision(d),
cout.width(w) і cout.precision(d).
Введення−виведення символьних масивів можна
здійснити за допомогою відповідних функцій заголовного файла stdio.h., наприклад:
·
для введення рядків — gets(st); та scanf (% s,st);
·
для виведення рядків — puts(st); і prin,tf(% s,st);.
У С рядки розглядалися як символьні масиви. Для роботи з
ними розроблено бібліотеку функцій string.h,
що містить ефективні засоби для роботи з рядками. Для обробки символьних типів
даних бібліотека функцій string.h
має велику кількість вбудованих функцій, що збільшують продуктивність праці
програмістів та скорочують час на розробку програм, наприклад:
·
функції перевірки символів;
·
функції перетворення символів;
·
функції перевірки рядків;
·
функції маніпулювання рядками.
Функції наводяться у вигляді списків, що згруповані за їх
розташуванням у заголовних файлах. Найчастіше надаються прототипи функцій, що
описують, як слід використовувати функції у програмах.
Далі розглянемо прототипи, стислий опис, дію та методику
застосування основних функцій обробки даних символьного типу.
Функції копіювання рядків:
char strcpy (s, *st); — виконує операцію копіювання байтів рядка st у рядок s(включаючи “\0”;
повертає s);
char
*strdup (const char *str); — виконує
копіювання рядка str і повертає
покажчик на рядок−копію;
char
* strncpy (char *st1, const char *st2, int n); — виконує копіювання n
символів з рядка st2 у st1
(рядок stl повинен бути більше
або дорівнювати st2, інакше
виникне помилка), наприклад:
char st1[ ] = “Паскаль “;
char st2[ ] = “Привіт з далеку “;
strnpy (st1, st2, 3); // st1 —
“Прикаль“.
Функції, конкатенації рядків:
char *strcat (char *st1, const char *st2); — поєднує st1 і st2 та повертає st1,наприклад:
char str [100];
strcpy (str, “Borland “);
strcat
(str, ” C++5″);,
у результаті маємо рядок
string = “Borland C++
char *strncat (char *st1, const char *st2, int n); — додає до рядка st1 n символів рядка st2 і повертає знову в st1, наприклад:
char
st1 [90] = “Привіт “;
char
st2 [50] = “студент и студентка”;
strncat
(st1, st2, 7);,
у результаті маємо рядок:
st1
= “Привіт студент ” .
Функції порівняння рядків:
int strcmp (char *stl, char
*st2);
— порівнює рядки st1 і st2 та
повертає цілу величину, що дорівнює:
<0 — якщо st1 < st2;
= 0 — якщо st1 = st2;
>0 — якщо st1 > st2;,
наприклад:
char st1[ ] = “Слово ” ;
char st2[ ] = “слово”;
int k;
k = strcmp (st1, st2);
//k<0;
int stricmp (const char *stl, const char *st2); — виконує порівняння рядків, не враховуючи регістра символів; повертає цілу величину, як і функція strcmp(),наприклад:
char st1[ ] = “Слово “;
char st2[ ] = “слово”;
int k;
k = stricmp (st1, st2); //k = 0;
int strncmp (char *stl, char *st2, int n); — виконує порівняння рядків із заданою кількістю символів n у st1 і st2 і повертає цілу величину:
<0 — якщо st1 < st2;
=0 — якщо st1 = st2;
>0 — якщо st1 > st2; ;
char *strnicmp (char *stl, char *st2, int n); — виконує порівняння рядків із заданою кількістю символів n у st1 і st2, незалежно від регістра, і повертає цілу величину, як і в попередньому випадку.
Функції перетворення символів рядка:
char *strlwr (char*st); —
перетворює символи рядка st верхнього регістра в символи нижнього регістра, при
цьому інші символи не враховуються. Наприклад:
char
st [ ] = ” Лазерный Принтер”;
strlwr
(st); // st = ” лазерный принтер” ;
char *strupr (char *st); —
перетворює символи рядка st нижнього регістра в символи верхнього регістра,
інші символи не враховуються;
char *strrev (char *st); —
записує символи в рядку st у зворотному порядку (реверсує рядок), наприклад:
char st [ ] = ” Hello”;
strrev (st); //st – ” olleH”;
char *strchr (char *st, int c);
— визначає перше входження символа с у рядок st;повертає покажчик на символ у рядку st, що відповідає введеному символу, наприклад:
char st [90] = ” Borland С++5 ”
char *spt;
spt= strchr (st, ‘+”); — тепер покажчик spt вказує на підрядок “++
char *strrchr (char *st, int
c); — знаходить останнє входження символа с у рядок st;якщо символ с у рядку не виявлений, повертає 0,
інакше повертає покажчик на останній символ у рядку st, що відповідає заданому зразку, наприклад:
char st [80] = “Borland С++
char *spt;
spt= strrchr (st, ‘+’); — покажчик spt вказує на підрядок “+
Функції
пошуку підрядка в рядку:
strspn (const char *st1, const
char *st2 ); — повертає кількість символів від початку рядка st1, що збігаються із символами рядка st2, де б вони не знаходилися в st2,наприклад:
char st1 [ ] = “Borland С++
char st2 [ ] = ” narlBod “;
int k;
k= strspn (sti, st2); — змінна k одержує значення, що дорівнює 8, тому що перші8 символів рядка містилися в st1(враховуючи символ пропуску);
char *strstr (const char *st1, const char *st2); — функція шукає в рядку st1 перше входження st2 і повертає покажчик на перший символ, знайдений у st1, з підрядкаst2; якщо рядок st2 не виявлений в st1, функція повертає 0, наприклад:
char
stl [ ] = “Привіт, однокурсник, ідем на екзамен”;
char st2[ ] = “однокурсник”;
char spt;
spt = strstr (stl, st2);
Результат виконання:
spt
= “однокурсник, идем на экзамен”.
За потреби визначення
останнього входження можна спочатку реверсувати рядок за допомогою функції strrew;
char *strtok (char *st,
const char *dlm); — розбиття рядка на лексеми (сегменти), обмежені символами,
що входять до складу рядка dim. Цей параметр може містити будь−яку кількість
різних обмежників — ознак границь лексем, після виділення лексеми в рядок st поміщається символ «\0».
Наступні виклики функції strtok() повинні бути з першим аргументом NULL. Вони будуть повертати покажчик на інші, наявні в st лексеми. Щоразу після завершення виділення лексеми у її кінці замість
розділового символа поміщається символ
«\0». Після того, як у рядку не залишиться жодної лексеми,
функція повертає NULL. Для збереження вихідного рядка його треба записати
в резервну змінну. Цю функцію зручно використовувати для розбиття речення на
слова або будь−які інші сегменти. Розглянемо приклад програми з
використанням функції strtok().
Приклад Скласти програму, яка
вводить речення, здійснює розбиття його на слова, підраховує кількість символів
у кожному слові та виводить відповідну інформацію
//
Використання функції
strtok()
/*
визначення порядкового номера слова в реченні и підрахунок кількості символів в
кожному слові */
#include
<string.h>
#include
<iostream.h>
#include
<conio.h>
voidmain
(void)
{ char *tk, *spt=", .!";
char st[ ] = "Роби велике, не обіцяючи
великого.";
cout << st<< endl;
int і
= 1;
tk = strtok
(st, spt);
while (tk !=
NULL)
{
cout << і << "
слово — " << tk << " — містить "
<< strlen(tk) << " символів" << endl;
tk
= strtok(NULL, spt); і++;}
getch
(); // затримка екрану
}
Результати виконання
програми:
Роби
велике, не обіцяючи великого
1 слово
— Роби — містить 4 символів
2 слово
— велике — містить 6 символів
3 слово
— не — містить 2 символів
4 слово
— обіцяючи — містить 8 символів
5 слово
— великого — містить 8 символів
Функції перетворення рядків у числа та чисел у рядки знаходяться у файлі stdlib.h:
int atoi (const
char *s); — перетворює рядок s у число типу int. Повертає отримане число 0, якщо зустрінеться
символ, що не може бути перетворений. Рядок повинен містити число, наприклад, «2345», та мати таку
структуру: [пропуски]
[знак числа] [цифри];
long atol (const char *s); —
перетворює рядок s
у число типу long
int (аналогічна функції atoi.);
double atof (const char *s); —
перетворює рядок символів у число з плаваючою крапкою типу double. Якщо зустрічається
символ, що не може бути перетворений, повертає 0. Оброблюваний рядок повинен мати таку
структуру: [пропуски]
[знак числа] [цифра.цифра] [літера е, Е, d або D] [знак порядку] [цифри
порядку], наприклад, «−12345.123»
або «−12.345123 ЕЗ»;
char *ecvt (double vl, int n, int *dec, int
*sign); — перетворює число vl у рядок символів,
кількість яких дорівнює n
символів цифр. Положення десяткової крапки від першої цифри числа повертається
до змінної, на яку вказує dec.
Знак числа повертається до змінної, на яку вказує sign. Якщо sign = 0, то число є
додатним, інакше — від’ємним. Отриманий рядок зберігається у внутрішній
пам’яті функції, покажчик повертається на початок сформованого рядка;
char *fcvt (double vl, int n, int *dec, int
*sign); — аналогічна до попередньої функції char *ecvt(), але якщо
для функції ecvt
параметр dec
задає загальну кількість цифр, то для функції fcvt — кількість цифр після десяткової
крапки;
char *gcvt (double vl, int n, char *buf); —
перетворює число vl
у рядок, котрий поміщає в буфер, покажчик на початок якого є buf, n — число цифр у
символічному записі перетвореного числа. Отриманий рядок містить символ знака
числа і десяткової крапки, якщо число містить менше десяткових цифр, ніж n. У цьому випадку
молодша цифра дробової частини відкидається. Якщо перетворене число не можна
помісити в задану кількість цифр n,
функція генерує символьний запис в експоненціальній формі із символом Е і знаком порядку.
Функція повертає покажчик на початок сформованого рядка;
strlen (st) —
повертає довжину змінної st
без нуль−термінала «\0».
Функції перевірки символів знаходяться у файлі ctype.h:
isgraph (s) — повертає значення
«істина» (1), якщо s є друкованим символом, і «неправда» (0),
якщо s є пропуском або яким−небудь не відображуваним символом;
isprint (s) — повертає значення
«істина» (1), якщо s є друкованим символом, включаючи символ пропуску,
і «неправда» (0) у всіх інших випадках;
ispunct (s) — повертає значення
«істина» (1), якщо s є знаком пунктуації (будь−який
друкований символ, крім пропуску), і «неправда» (0) в інших випадках;
isdigit (s) —
повертає значення «істина» (1), якщо s є цифрою від 0 до 9, і «неправда»
(0) в інших випадках;
isalmim (s) — повертає значення
«істина» (1) якщо s є цифрою або літерою (заголовною або строковою), і
«неправда» (0) у всіх інших випадках (тобто перевіряє алфавітні та
цифрові символи).
Функції перетворення символів:
tolower (s) —
перетворює символ s до нижнього регістра;
toupper (s) — перетворює символ
s до верхнього регістра;
atoi (s) — перетворює рядок s
до цілого числа;
atol (s) — перетворює рядок s
до довгого цілого;
atof (s) — перетворює рядок s
до числа з плаваючою крапкою.