Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Глинський С++.docx
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
2.26 Mб
Скачать

Тема 12. Рядки

  1. Рядки символів і дії з ними. На відміну від інших мов програмування у C++ не визначено спеціального типу для опрацювання рядків. Рядок символів розглядається як масив елементів типу char, який закінчується символом ’\0’ (нуль-символ), що є ознакою кінця рядка. Такі рядки називають ASCII-рядками. Сталі типу рядок записують у лапках, на­приклад, "Львівська політехніка", "студенти", " " - рядок, що містить один символ-пропуск. У сталих рядках нуль-символ дописується автоматично.

Зауваження 1. Більшості компіляторів мови C++ автоматично додає нуль-символ у кінець рядка, тому зазначати його не обов’язково.

Масиви символів оголошують так:

char <назва рядка>[довжина рядка];

вами символів, то назва рядка є вказівником на його перший елемент (на перший символ).

Приклад 1. Розглянемо оголошення та ініціалізацію ряд­ків

const char text1[] = "Ми вивчаємо програмування";

char slovo[] = “University";

char fraza1[11], fraza2[40];

Тут оголошено сталу text1, яка має значення "Ми вивчаємо програмування", символьні масиви: slovo (без зазначення роз­міру), fraza1 (може містити до 10 символів) та fraza2 (до 39 сим­волів).

Символьний масив slovo ще можна оголосити так:

char slovo[11] = "University”; або так

char slovo[] = {'U', 'n', 'і', ' v' , 'e', 'r', ' s',' i', 't', 'y', '\0'};

Тут потрібно вручну записати нуль-символ, інакше компі­лятор трактуватиме змінну slovo не як рядок, а як масив.

Рядки можна опрацьовувати посимвольно за допомогою вказівників або назви масиву, наприклад, так:

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

*(fraza1 +n) = *(slovo+n);

cout<<fraza1;

Змінній frazal надається значення "University" і ця фраза виводиться на екран. Інакше це можна зробити так:

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

fraza1[n] = slovo[n];

cout<<fraza1;

Увести весь масив символів можна за допомогою команди

сіn>> <назва масиву>;

Якщо рядок даних містить символ пропуску, то команда сіn>> зчитає дані лише до першого пропуску. Щоб зчитати весь рядок до символу вводу, необхідно застосувати команду

cin.get(<нaзва рядка>, <максимальна довжина рядка>);

Наприклад, cin.get(fraza2, 40). Зчитати символ вводу можна так: cin.get(). Зчитати рядок разом із символом вводу можна одним із способів:

  1. cin.get(fraza2, 40); cin.get()

  2. cin.get(fraza2, 40).get()

  3. cin.getline(fraza2, 40).

Вивести значення рядка на екран можна за допомогою ко­манди

cout<< <назва рядка>;

Посимвольно вводити чи виводити елементи рядка можна за допомогою команд циклу for або while. Наприклад,

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

cin>> *(fraza1 + n);

В кінці рядка необхідно поставити нуль-символ, тобто *(fraza1 + n + 1) = '\0';

У бібліотеці conio.h визначені стандартні функції введення-виведення рядків. Наприклад, getc(), getchar() зчитують по одному символу рядка, введеного з клавіатури, putc() та initchar() виводять окремі символи рядка тощо. У бібліотеці stdio.h описані функції для введення gets() та виведення puts() усього рядка. Детальніше про ці та інші функції написано у довідниках.

  1. Функції для опрацювання рядків. Для опрацювання масивів символів у мові C++ є стандартні функції, які опи­сані у модулі string.h. Розглянемо деякі з них.

strlen(<pядок>) - визначає фактичну кількість символів у рядку, застосовується у виразах; strcat(r1, r2) - команда з’єднання рядків r1, r2 в один ря­док, результат присвоює змінній r1; strncat(r1, r2, n) - до змінної r1 додає перших n символів рядка r2;

strcpy(r1, r2) - копіює символи з рядка r2 в рядок r1;

strncpy(r1, r2, n) - копіює перших n символів рядка r2 в рядок r1;

strchr(r1, <символ>) - визначає перше входження деякого символу у рядок r1 так: повертає рядок, який почи­нається від першого входження заданого символу до кінця рядка r1, застосовується у виразах;

strrchr(r1, <символ>) - визначає останнє входження зада­ного символу у рядок, застосовується у виразах;

strspn(r1, r2) — визначає номер першого символу, який входить у рядок r1, але не входить у рядок r2, застосовується у виразах;

strstr(r1, r2) — визначає в рядку r1 підрядок, що починаєть­ся з першого входження рядка r2 у рядок r1, засто­совується у виразах;

strtok(r1, r2) - визначає частину рядка r1, яка закінчується перед першим однаковим символом рядків r1 та r2;

strnset(r1, <символ>, n) - вставляє n разів заданий символ перед рядком r1, застосовується у виразах;

strupr(r1) - перетворює усі малі літери рядка у великі;

strlwr(r1) - перетворює усі великі літери рядка у малі;

strrev(r1) - записує рядок у зворотному порядку.

Приклад 2. Розглянемо результати застосування функцій до таких змінних:

char Lviv[] = "Львівська політехніка",

Un [30] = "НУ ", r1 [30] ="";

char *р; int n;

Застосування функцій

Результат

n = strlen(Lviv)

n=21

strcat(Un, Lviv)

Un = "НУ Львівська політехніка"

strncat(Un, Lviv, 10)

r1 = "НУ Львівська"

strcpy(r1, Lviv)

r1 = "Львівська Політехніка"

strncpy(r1, Lviv, 10)

r1 = "Львівська"

p = strchr(Lviv, 'П')

р = "політехніка"

p = strrchr(Lviv, 'i')

р = "іка"

n = strspn(Lviv, "Львів")

n = 5

p = strstr(Lviv, "тех")

р = "техніка"

p = strtok(Lviv, "kc")

р = "Львів"

p = strnset(Lviv, 'x', 10)

р = "ххххххххххполітехніка"

p = strupr("I Love You")

р = "I LOVE YOU""

p = strlwr("I Love You")

p = і love you"

p = strrev("техніка")

р = "акінхет"

Зауваження 2. Функції перетворення літер strlwr і strupr діють лише для латинського алфавіту. Крім того, у деяких версіях мови C++ ці функції можуть записуватись інакше: _strlwr, _strupr.

У бібліотеці stdlib.h є стандартні функції перетворення типів даних. Зокрема,

функція atoi(r1) перетворює рядок сим­волів r1 у дане цілого типу int,

функція itoa(<числове дане>, r1, <система числення>) - дане цілого типу int у рядок r1. Для пере­творення даних типу double у рядок символів визначена

функ­ція gcvt(<числове дане>, <кількість знаків у числі>, r1), а обернену дію виконує

функція strtod.

Приклад 3. Розглянемо результати дії функцій для оголошених нижче змінних.

int n; double f; char r1 [5], *p;

Застосування функції

Результат

n = atoi("12")

n = 12

itoa(12, r1, 10)

r1 ="12"

gcvt(-3.14, 4, r1)

r1 =-3.14

f = strtod("-3.1415", &p);

f = -3.1415

Рядки символів можна порівнювати між собою. Два ряд­ки порівнюють зліва направо посимвольно, причому 'А' < 'В', 'В' < 'С тощо. Більшим уважається символ, який розміще­ний в алфавіті дальше (він має більший номер у таблиці кодів ASCII). Для порівняння рядків у модулі string.h є такі функції:

  • strcmp(r1, r2) - порівнює рядки символів r1 і r2 з ураху­ванням регістра для латинського алфавіту;

  • stricmp(r1, r2) - порівнює рядки r1 і r2, не розрізняючи великих і малих літер латинського алфавіту.

Результатом виконання цих функцій є

  • від’ємне число (якщо рядок r1 менший від рядка r2),

  • 0 (якщо рядки однакові)

  • додатне число (рядок r1 більший за рядок r2).

Приклад 4. Розглянемо результат дії функцій

Функція

Результат

n = strcmp("Becнa", "весна")

n=-32

n = strcmp("вecнa", "Весна")

n =32

n = strcmp("Becнa", "Весна")

n =0

n = stricmp("Becнa", "весна")

n =-32

n = stricmp("Vesna", "vesna")

n = 0

Задача 1 (про довжину фрази). Увести рядок символів та ми визначити його довжину.

Зробимо це двома способами:

  1. за допомогою вказівника типу char і виділення дина­мічної пам’яті:

#include <iostream> // Довжина рядка символів

using namespace std;

int main(int argc, char** argv) {

char *s; // Оголошуємо вказівник на рядок

s = new char[50]; // Виділяємо пам'ять для введення рядка

cin >> s;

int d = 0;

while (*s++) d++;

cout<< d;

}

  1. визначивши різницю адрес першого й останнього сим­волів:

#include <iostream> // Довжина рядка символів

using namespace std;

int main(int argc, char** argv) {

char *s, *p; //Оголошуємо вказівники

s = new char[50]; // Виділяємо пам'ять для введення рядка

cin>> s;

p = s; // Вказівник р вказує на перший символ рядка

while (*s++); int d; // Вказівник s тепер вказуватиме на останній символ рядка

d = s - p-1; // Визначаємо довжину рядка як різницю адрес

cout<< d;

}

Задача 2 (про пошук слова у фразі). Нехай задано рядок "Скоро будуть канікули". Визначити довжину рядка. Вивести на екран фразу з другого слова цього рядка.

#include <iostream> // Пошук другого слова за допомогою функцій

#include <string.h>

using namespace std;

int main(int argc, char** argv) {

char r1[] = "Скоро будуть канікули";

char *p;

cout << r1 << "\n";

cout << "Довжина рядка r1 = " << strlen(r1) << "\n";

p = strchr(r1, ' '); // Встановлюємо вказівник p на перший пропуск у рядку r1

strtok(p,""); //З рядка р вилучаємо всі символи після його першого пропуску

cout<< p;

}

Задача 3. Вивести друге слово фрази задачі 2, при цьому ря­док розглядається як масив символів і функції для роботи з рядками не використовуються.

#include <iostream> // Рядок як масив символів

#include <conio.h>

#include <cstring>

using namespace std;

int main(int argc, char** argv) {

char r1[] = "Скоро будуть канікули";

char *p;

int n1, n2, k, m;

m = 0;

k = strlen(r1);

for (int i=0;i<k;i++) // Переглядаємо всі символи рядка

if (r1[i] ==' ') { //Шукаємо пропуск

m++;

if (m == 1) //Визначаємо номери першого

n1 = i;

if (m == 2) // та другого пропусків

n2 = i;

}

for (int i=n1+1;i<n2-1;i++)// Виводимо слово між двома пропусками

cout<< r1 [i];

getch();

}

Задача 3 (про столиці). Введіть п’ять назв столиць європейських країн. Упорядкуйте їх за алфавітом. Виведіть упорядкований масив виведіть на екран.

#include <iostream> // Столиці країн

#include <cstring>

#include <cstdlib>

#define N 5

using namespace std;

int main(int argc, char** argv) {

char p[N][16]; char m[16]; // Оголошуємо N вказівників на рядки довжиною до 15 символів

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

cin>> *(p +i); // Вводимо рядок і

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

for (int j = 0; j < N - i; j++) {

if (strcmp(p[j], p[j+1]) > 0) {

strcpy(m, p[j]); // Порівнюємо рядки і у разі потреби, міняємо їх місцями

strcpy(p[j], p[j+1]);

strcpy(p[j+1], m);

}

}

}

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

cout<< p[i] << "\n";

}

  1. Криптографічні задачі. Текстові функції застосовують для розв’язування задач кодування даних з метою збереження секретності інформації. Існує наука - криптографія,де вивчаються і створюються різні алгоритми кодування ін­формації. Основні задачі криптографії - це шифрування тексту, передача його на відстань і дешифрування. Це використовується у банківських справах, у воєнних цілях, у діяльності різних фірм, під час пересилання інформації в локальних чи глобальних мережах тощо.

Древнєримський імператор Цезар кодував свої секретні вказівки так: кожна літера тексту замінювалась на четверту після неї літеру з алфавіту. Такий шифр називається в крип­тографії шифром зі сталим зміщенням (тут 4), або шифром з одним ключем.

Задача 5 (про шифр Цезаря). Скласти програму для ко­дування деякого тексту до 50 символів шифром Цезаря, замі­нивши кожну літеру на 4-ту (наприклад, четверту) після неї літеру з алфавіту. Під алфавітом розуміти таблицю кодів ASCII.

#include <iostream>// Програма Код Цезаря

#include <cstring>

using namespace std;

int main(int argc, char** argv) {

char a[50];

cout<< "Введіть текст\n";

cin.get(a, 50);

for (int k, n = 0; n < strlen(a); n++) {

k = *(a+n) + 4; *(a + n) = k;

}

cout<< a;

}

Задача 5 (про заміну слів). Скласти програму, яка скрізь у заданому тексті mytext замінить деяке слово іншим словом такої ж довжини (word1 на word2).

#include <iostream> // Програма заміна слів

#include <cstring>

using namespace std;

int main(int argc, char **argv) {

char word1 [5], word2[5], mytext[50]; char *p;

cout <<"Введіть текст\n";

cin.get(mytext, 50);

cout << "Введіть шукане слово\n";

cin>> word1;

cout<< "Введіть інше слово\n";

cin >> word2;

int k = strlen(word1);

p = mytext; // Встановлюємо вказівник р на початок рядка mytext

for (int і = 0; і < strlen(mytext) - k; і++) { // Опрацьовуємо посимвольно рядок р

p = strstr(p, word1); // Знаходимо перше входження word1 у рядку р

if (p == NULL) break; //Якщо такого входження немає, то виходимо з циклу

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

*(p + j) = *(word2 + j);// У рядку р замінюємо word1 на word2

}

cout<< mytext;

}

Вправи

  1. Складіть програму розв’язування задачі 1, використавши статич­ний масив та функцію srtlen.

  2. Уведіть фразу з кількох слів і виведіть її так, щоб усі слова були зображені в зворотному порядку, зберігши порядок слів, двома способа­ми: а) з використанням функцій з бібліотеки string.h; б) без використан­ня функцій з бібліотеки string.h. Наприклад, фразу "заняття з програ­мування" треба вивести так: "яттяназ з яннавумаргорп" (модифікуйте для цього програму Рядок як масив символів).

  3. Розв’яжіть задачу про столиці країн без застосування функцій з модуля string.h.

  4. Модифікуйте програму Код Цезаря, щоб можна було зашифрувати текст, уведений у декілька рядків.

  5. Складіть програму розшифровування тексту, закодованого кодом Цезаря.

  6. Складіть програму кодування тексту так: перший символ замінити на k-й, що розміщений в алфавіті після нього (тобто замінити з кроком заміщення k), кожний наступний символ замінювати з кроком зміщення на т одиниць більшим, ніж попереднє зміщення. Алфавіт (таблицю кодів чи її фрагмент) розглядати циклічно. Наприклад, обмежимося алфавітом 0, 1, 2, 3, 4, 5, 6, 7, 8, 9. Для k = 2, т = 1 чисельність військового гарнізону 12290 вояків буде зашифрована числом 35646. Такий шифр називається шифром зі змінним зміщенням (або шифром з двома ключами).

  7. Запишіть програму Заміна слів без використання функцій з бібліо­теки string.h.

  8. Закодуйте фразу так: вилучіть з неї пропуски та коми, інші символи продублюйте. Вивести результат.

  9. Масив зі 100 рядків і 10 стовпців заповніть цілими числами, що вводяться з клавіатури. Якщо чергове число менше від 0, заповнення такого рядка припиніть. Після чисел у кожному рядку запишіть ще од­не? число - кількість чисел у ньому. Виведіть масив.

  10. Розв’яжіть задачі № 16, 17 і 18 з розділу "Задачі" вашого варіанта двома способами:

а) з використанням функцій з бібліотеки string.h;

б) без використання функцій з бібліотеки string.h.