Основні функції обробки символьних типів

У ранніх версіях С++ рядки розглядалися як символьні масиви. Для роботи з ними розроблено бібліотеку функцій string.h, що містить ефективні засоби для роботи з рядками. Згодом була розроблена стандартна бібліотека шаблонів Stan­dard TemplateLibrary (STL), яка надає більш потужні засоби, об’єднані в клас string. Але незважаючи на існування цього окремого для рядків класу, символьні масиви, що закінчуються нульовим байтом ‘\0’, залишаються досить популярними. Це відбувається завдяки їх ефективності і можливості контролю­вання операції з рядками.

Для обробки символьних типів даних бібліотека функцій string.h має велику кількість вбудованих функцій, що збіль­шують продуктивність праці програмістів та скорочують час на розробку програм, наприклад:

  • функції перевірки символів;
  • функції перетворення символів;
  • функції перевірки рядків;
  • функції маніпулювання рядками.

Функції наводяться у вигляді списків, що згруповані за їх розташуванням у заголовних файлах. Найчастіше надаються прототипи функцій, що описують, як слід використовувати функції у програмах (див. розділ 9).

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

Функції копіювання рядків:

  • char strcpy (s, *st); — виконує операцію копіювання байтів рядка st у рядок s(включаючи  “\0”; повертає s), на­приклад:

char str [50];

strcpy (str, “О деле суди по исходу.”);

 

  • char *strdup (const char *str); — виконує копіювання рядка str і повертає покажчик на рядок-копію, наприклад:

char “st1 = “Слово — есть поступок.”;
char *st2;

st2 = strdup (st1);           //копируется st1 в st2;

 

  • 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++5”;

 

  • 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 вказує на підрядок “++5” рядка st;

 

  • char *strrchr (char *st, int c); — знаходить останнє вхо­дження символа с у рядок st;якщо символ с у рядку не вияв­лений, повертає 0, інакше повертає покажчик на останній сим­вол у рядку st, що відповідає заданому зразку, наприклад:

char st [80] = “Borland С++5”; 

char *spt;

spt= strrchr (st, ‘+’); — покажчик spt вказує на підрядок “+5” ряд­ка st.

 

Функції пошуку підрядка в рядку:

  • strspn (const char *st1, const char *st2 ); — повертає кількість символів від початку рядка st1, що збігаються із сим­волами рядка st2, де б вони не знаходилися в st2,наприклад:

char st1 [ ] = “Borland С++5”; 

char st2 [ ] = ” narlBod “; 

int k;

k= strspn (sti, st2); — змінна одержує значення, що дорівнює 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().

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

// Р7 1.СРР — применение функции 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  слово — Делай — содержит 5 символов
2  слово — великое — содержит 7 символов
3   слово — не — содержит 2 символов
4   слово — обещая — содержит 6 символов
5   слово — великого — содержит 8 символов
Процес розбиття речення на слова можна було б здійснити з використанням і такого програмного фрагмента:
tk = strtok (st < spt); // первый вызов функции
while (tk)
if ((tk = strtok(), spt) != 0) cout <<. . ..
Для видалення з рядка підрядка або символа із заданої позиції у бібліотеці string.h немає спеціальної функції, однак можна написати власну, наприклад:

void del (char *st, int k, int n); 
{
  for (int і = k; і < strlen(st); i++)
  st[i] = st [i + n];
  st[i] =’\0′;               // запись “\0” в конец новой строки
}
де st — вихідний рядок (покажчик на нього);
    n — кількість символів у підрядку, що вилучається;
    k — позиція, з якої треба вилучити підрядок. Наведемо приклад, котрий ілюструє використання функції void del (); (детальніше про функції див. в розділі 9).

Приклад 7.2. Скласти програму вилучення підрядка в n символів з k-ої позиції в рядку.

/* Р7 2.СРР — удаление подстроки в п символов из k-ой позиции в строке */
#include <iostream.h> 
#include <string.h> 
#include <conio.h>
//--------------- функция удаления подстроки из строки
void del (char*sp, int k, int n)
{ int і;  
  for (і = k; і < strlen(sp); і++)
  sp[i] = sp[i+n]; 
  sp[i] = \0';}
main ()           //----------- главная функция
{ char st[50], pst[10]; 
  cout << "***** Введите строку\n"; 
  cin.getline(st, 50);
  cout << "***** Введите подстроку\n";
  сіn >> pst;
  cout << "Исходная строка: — "<< st << endl;  
  del (st, strstr(st, pst)-st, strlen(pst));  
  cout << "Новая строка: — "<<st<<endl;  
  getch();
}

Результата обчислень:
***** Введите строку
Люблю писать программы на языке С++!
***** Введите подстроку
писать
Исходная строка: — Люблю писать программы на языке С++! 
Новая строка: — Люблю программы на языке С++!

  • void* memchr (const void *st, int s, int n); — функція шукає символ “s у рядку *st довжиною n байт, тобто в блоці пам’яті, на який вказує покажчик st. Якщо символ sзнайде­ний, функція повертає покажчик на цей символ, а в протилеж­ному випадку —повертає NULL;
  • void* memcmp (const void *s1, const void *s2, n); і void* memicmp (const void *sl,const void *s2, int count); — функції по­рівнюють n байт з двох буферів, на початок яких указують s1 і s2.

Функції повертають значення

<0 — якщо s1 < s2;
=0 — якщо s1 = s2;
>0 — якщо s1 > s2;;

  • char *strset (char *st, int ch, int n); і char *strset (char *st, int ch); — функції заповнюють рядок st символом ch і по­вертають покажчик на отриманий рядок, n —заповнює n сим­волів рядка st.

Функції перетворення рядків у числа та чисел у рядки знаходяться у файлі 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 до числа з плаваючою крапкою.

 

Розглянемо приклади з використанням рядкових функцій.
 
Приклад 7.3. Ввести до пам’яті комп’ютера список прізвищ, які розташовані в будь-якому порядку, та відсортувати їх за алфавітом.
Розглянемо перший варіант (див. Р7_3_1.СРР) реалізації поставленої задачі. Будемо вважати, що вводять прізвища та ініціали, тоді програма може мати вигляд:

// Р7 3 1.СРР — отсортировать фамилии по алфавиту
#include <iostream.h> 
#include <string.h>
#include <conio.h>
main( )
{ const int n=5;
  char sp[n][l5], r[15];
  int i, k;
//------------------------------- ввод фамилий и инициалов
cout<< "***** Введите " << n << " фамилий \n"; 
  for (і = 0; і < n; і++)
 { cout<<"Введите "<<(і+1)<<" фамилию и инициалы\n"; 
     cin.getline (sp[i], sizeof (sp[i]) - 1); 
   }
//------------------------------ сортировка списка фамилий
  for (k = 1; k < n; k++) 
    for (i = 0; і < n-k; i++)
    if (strcmp (sp[i], sp[i+l])>0) 
    { strcpy (r, sp[i]);
      strcpy (sp[i], sp[i+1]);
      strcpy (sp[i+1], r);}
  cout<<"\n Отсортированный массив фамилий \n";
  for (і = 0; і < n; i++)  
  cout << sp[i] << endl;
  getch ();  
}

Результати обчислень:
******* Введите 5 фамилий
Введите 1 фамилию и инициалы
Иванченко С. И.
Введите 2 фамилию и инициалы
Авдиенко А. Р.
Введите 3 фамилию и инициалы
Яшин Б. Ю.
Введите 4 фамилию и инициалы
Кашкин Т. Б.
Введите 5 фамилию и инициалы
Мельниченко Т. Ю.
Отсортированный массив фамилий
Авдиенко А. Р.
Иванченко С. И.
Кашкин Т. Б.
Мельниченко Т. Ю.
Яшин Б. Ю.

У наведеній програмі використано масив прізвищ sp [6][15] і символьний рядок r, який потрібен для тимчасового зберіган­ня прізвища при сортуванні масиву. Для сортування був засто­сований раніше розглянутий метод виштовхування («пухирця») (див. розділ 6.4).

Порівняння елементів символьного масиву (char sp[n][15]) здійснюється за допомогою функції strcmp( ), а перезапис прі­звищ з одного елемента масиву sp[i] в другий — sp[i+1]— за допомогою функції strcpy( ) і змінної r.

Після сортування на екран виведено одержаний масив. Другий варіант (див.Р7_3_2.СРР) розв’язання поставленої задачі використовує покажчики.

/* Р7_3_2.СРР — сортировка списка фамилий в алфавитном порядке с использованием указателей */
#include <iostream.h>
#include <string.h>
#include <conio.h>
void main( )
{ const n=5; 
  char sp [n][15];
  int i, k;
  char *ps[n], *ptr; //ps[n] — массив указателей 
// ввод фамилий и инициализация массива указателей
 cout << "***** Введите фамилии \n"; 
  for (і = 0; і < n; і++) 
  { gets (sp [і]);   
    ps[i] = sp[i];}
//--------------------------- вывод исходной информации
  cout << "\n***** Исходный список\n"; 
  for (і = 0; і < n; і++)   
  puts (ps[i]);
//------------------------------------ сортировка массива
  for (k = 1; k < n; k++)   
    for (i = 0; i<n-k; i++)   
    if (strcmp (ps[i], ps[i+1]) > 0)    
    { ptr = ps[i];      
      ps[i] = ps[i+1];      
      ps[i+1] = ptr;   }
//--------------------- вывод отсортированного массива
  cout << "\n\n*****Отсортированный список \n"; 
  for (і = 0; і < n; і++)   
  puts (ps[i]); 
  getch ();  
}

Результати виконання програми:
***** Введите фамилии 
Игнатенко А. P. 
Головко Н. А.
Долбня Б. В. 
Андриенко С. Ф. 
Ичко Т. В.
***** Исходный список
Игнатеяко А. Р. 
Головко Н. А. 
Долбня Е. В. 
Андриенко С. Ф. 
Ичко Т. В.
***** Отсортированный список
Андриенко С. Ф.
Головко Н. А.
Долбня Е. В.
Игнатенко А. Р.
Ичко Т. В.
 
Приклад 7.4. Ввести рядок і видалити в ньому зайві пропуски.

// Р7 4.СРР — удаление лишних пробелов в строке
#include <iostream.h> 
#include <string.h> 
#include <conio.h>
void main() 
{ char st[ ] = "Краткость — сестра таланта";
  int і, n = 0;    //n — для подсчета пропусков
 for (і = 0; і < strlen(st); i++) 
  { if (st[i] != ' ')     
    { cout « st[i];  
       n=0; }      
    else n++;     
    if (n == 1)  
    cout << st[i];   }
  getch();
}

Результати виконання програми:
Краткость — сестра таланта
Приклад 7.5. Визначити позицію входження підрядка в рядок.

// Р7 5.СРР — поиск позиции вхождения подстроки в строку
#include <iostream.h>
#include <string.h>
#include <conio.h>
const int m = 50;
void main() 
{ char *pt, mainstr[m], substr[m];
  int n, k = 0;
  cout << "***** Введите строку " << endl;
  cin.getline (mainstr, m);
  cout << "***** Введите подстроку " << endl;
  cin.getline (substr, m);
  pt = strstr (mainstr, substr);
  cout << endl;
  while (pt) 
  { k++;      // номер вхождения 
   n = pt - mainstr;  
    cout << k <<" -oe вхождение подстроки" <<" номер позиции = "<< n << endl;
    pt = strstr(++pt, substr);
    cout << k << " " << *pt << endl;}
  if (k == 0) cout <<"Подстрока не содержится в строке"<<endl;
  getch();
}

Результат виконання:
***** Введите строку
Почти во всех делах самое трудное — начало. 
***** Введите подстроку 
самое трудное
1-ое вхождение подстроки номер позиции = 20
Приклад 7.6. Знайти заданий символ у рядку.

// Р7 6.СРР — поиск символа в строке
#include <iostream.h> 
#include <string.h> 
#include <conio.h>
main( )
{ const int m = 50; 
  char sim, *pt, str[m];
  int n, k = 0;
  cout << "***** Введите строку" << endl;
  cin.get (str, m);
  cout << "***** Введите символ" << endl;
  сіn >> sim;
  pt = strchr (str, sim);
  while (pt)
{ k++;
    n = pt-str;
    cout<<k<<"-я позиция вхождения символа = "<<n<<endl;
    pt = strchr(++pt, sim); }
cout << "Количество вхождений = "<<k<<endl;
  if (k==0) cout << "Символ не входит в строку" << endl;
 getch();
}

Результати обчислень:
***** Введите строку
Алгоритм — фундаментальное понятие информатики 
***** Введите символ 
и
1-я     позиция входения символа = 5
2-я     позиция входения символа = 32
3-я     позиция входения символа = 35
4-я     позиция входения символа = 43
5-я     позиция входения символа = 45
Количество вхождений = 5

Приклад 7.7. З уведеного списку прізвищ (без ініціалів) вилучити такі, що починаються на задану літеру і мають задане закінчення, та вивести повідомлення про прізвище з найменшою кількістю літер.

/* P7_7.CPP — найти фамилии, начинающиеся на заданную букву и имеющие заданноеокончание */
#include <iostream.h>
#include <string.h>
#include <conio.h> 
main()
{ const int n = 6; 
  char spis [n][15], pok[5], p;
  int i, minfam, k=0;
//------------------------------ ввод списка фамилий без инициалов
cout << "***** Введите "<<n<<" фамилий\n";
 for (і = 0; і < n; i++)
  сіn >> spis [і];
  cout << "***** Введите первую букву\n";
  сіn >> р;
  cout << "**** Введите окончание\n";
  сіn >> роk;
// определение фамилии на заданную букву и на заданное окончание
 cout << "***** Искомые фамилии\n";
  for (і = 0; і < n; і++)
  if (spis [i][0]==p && strcmp(strrchr(spis[i], pok[0]), pok)==0) 
  cout<<spis [i]<<endl;
//-------------- поиск фамилии с наименьшим количеством букв
  minfam - strlen (spis [0]);
  for (і = 1; і < n; і++)
  if (strlen (spis [і]) < minfam)
  { minfam = strlen (spis[i]);
     k=і; } 
  соut<<"\Фамилия с наименьшим колич. букв — "<<spis [k]<<" \n";
  cout << "Её длина = " << strle(spis [k]) << " символов\n";
  getch ();  
}

Результати обчислень:
***** Введите 6 фамилий
Андриенко
Коваленко
Степаненко
Курко
Коноваленко 
Перекотиполе
***** Введите первую букву 
К
***** Введите окончание
ко
***** Искомые фамилии
Коваленко
Курко
Коноваленко
Фамилия с наименьшим колич. букв — Курко 
Её длина = 5 символов

У програмі для зберігання першої літери використовується змінна з ім’ям р, а для закінчення — змінна роk. Вилучення за­кінчення прізвища здійснює функція strrchr(spis[i],pok[0]), яка повертає покажчик на останнє входження заданої літери (рок[0]) у рядок(spis[i]). Потім цей покажчик порівнюється з введеним закінченням прізвища за допомогою функції strcmp(). У цілому в операторі if… визначається як перша літера, так і закінчення прізвища. Змінна minfam існує для знаходження прізвища з най­меншою кількістю літер згідно з алгоритмом визначення мінімального елемента масиву (див. приклад 1.3).

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *