- •1 Масиви
- •2 Рядки і символи
- •Реализация в языках программирования
- •[Править] в языке Си
- •Урок 6. Класс string
- •Класс string
- •Упражнение 3.15
- •Клас string: конструктори і присвоєння рядків, операції, відкладене копіювання Клас string: конструктори і присвоєння рядків, операції, відкладене копіювання
- •Упражнение 3.12
- •Упражнение 3.13
- •Упражнение 3.14
- •2 Рядки і символи
2 Рядки і символи
Рядок являє собою масив символів, що закінчується нуль-символом. Нуль символ – це символ з кодом 0. Може записуватися у вигляді керуючої послідовності ’\0’.
Приклади
char s1[15];
unsigned char m[10];
При описі рядок може бути ініціалізований строковим літералом (послідовність символів, узята в подвійних лапки), нуль-символ при цьому додається компілятором автоматично.
Приклад
char s[10]=”stroka”;
У цьому випадку для рядка s виділяється 10 байт пам'яті, шість байт будуть зайняті під символи рядка, сьомий – під нуль символ.
Якщо рядок при визначенні ініціалізується, то його розмірність можна опустити (компілятор сам виділить потрібне число байт).
Приклад
char s[]=”stroka”;
Операція присвоювання одного рядка іншої не визначена (тому що рядок є масивом) і повинна виконуватися за допомогою циклу або функцій стандартної бібліотеки.
Введення/виведення символів
Для зчитування коду символу з клавіатури без відображення символу на екрані використовується функція getch().
Функція getch читає з консолі без відображення символу на екран.
Функція чекає натискання будь-якої клавіші і повертає її код для використання. Функції потрібна бібліотека: conio.h.
Функцією printf() зручно користатися в тих випадках, коли потрібно вивести дані різних типів.
Завдання 1
Продемонструємо використання функцієї getch для зчитування коду символу з клавіатури без відображення на екрані, а потім виведемо цей символ на єкран.
Текст програми:
#include <stdio.h>
#include <conio.h>
#include <windows.h>
void main()
{
char ch;
ch=getch(); //Введення символу
printf("Input string=%c",ch);
printf("\n");
system("pause");
}
Компілюємо програму і бачимо результат.
Результат
Примітка – Для функціональних клавіш функцію getch() необхідно застосувати двічі, тому що при їхньому натисканні генерується двохсимвольний код (перший символ – нульовий).
Функція getchar() читає символ з клавіатури, а putchar() відображає символ на екрані. Перша з цих функцій очікує, поки не буде натиснута клавіша, а потім повертає значення цієї клавіші. Крім того, при натисканні клавіші на клавіатурі на екрані дисплея автоматично відображається відповідний символ. Друга ж функція, putchar(), відображає символ на екрані в поточній позиції курсору.
Завдання 2
Продемонструємо використання функції getchar для зчитування символу з клавіатури, а потім виведемо цей символ на єкран функцією putchar.
Текст програми:
#include <stdio.h>
#include <windows.h>
void main()
{
char ch;
ch=getchar(); //введення символу
putchar(ch); //виведення символу
printf("\n");
system("pause");
}
Компілюємо програму і бачимо результат.
Результат
Введення/виведення рядків
Функція gets() зчитує символи з клавіатури до появи символу ‘\n’ (натискання на Enter) і поміщає їх у рядок. При цьому в рядок замість символу ‘\n’ заноситься нуль-символ.
Завдання 3
Продемонструємо використання функції gets для зчитування символів з клавіатури.
Текст програми:
#include <stdio.h>
#include <windows.h>
void main()
{
const int n=20;
char st[n];
printf("Enter a string=");
gets(st);
printf("Input string=%s\n",st);
system("pause");
}
Компілюємо програму і бачимо результат.
Результат
Якщо потрібно виведення тільки рядків, то краще використовувати функцію puts().
Функція puts() виводить рядок на стандартний пристрій виведення, при цьому нуль-символ заміняється на символ нового рядка ‘\n’. Повертає позитивне значення при успішному виведенні і EOF при помилці.
Завдання 4
Продемонструємо використання функції gets для зчитування символів з клавіатури, а потім використання функції puts для виведення цих символів на єкран.
Текст програми:
#include <stdio.h>
#include <windows.h>
void main()
{
const int n=20;
char st[n];
printf("Enter a string=");
gets(st);
puts(st);
system("pause");
}
Компілюємо програму і бачимо результат.
Результат
Поняття потоку
У мові С++ основним поняттям введення та виведення даних є потік — послідовність символів або інших даних. У програмі потік зображує фізичний файл на зовнішньому носії даних (диску, клавіатурі або екрані монітора), тобто фізичний файл «видно в програмі» як потік даних. Операції обміну даних з файлом представлено в програмі як операції добування даних з потоку або дописування їх до нього.
У програмуванні існує поняття стандартних файлів введення та виведення — як правило, ними є клавіатура та екран. У С++-програмі їм відповідають стандартний потік введення з ім’ям cin та стандартний потік виведення з ім’ям cout. Отже, імена cin і cout, означені у файлі iostream, насправді позначають не клавіатуру та екран, а потоки, що відповідають цим пристроям у програмі. На початку виконання програми обидва потоки cin і cout порожні.
З засобів обробки потоків розглянемо лише операції введення >>, або вставки (insertion), даних з вхідного потоку, та виведення <<, або вставки, даних у вихідний потік.
!!! Найкращий приклад просторів імен можна знайти в стандартній бібліотеці С + +. Всі функції, класи, об'єкти і шаблони стандартної бібліотеки оголошені всередині простору імен std.
Завдання 5
Продемонструємо використання операції введення >> з потоку для зчитування символів з клавіатури, а потім використання операції виведення << для виведення цих символів у потік.
Текст програми:
#include <iostream> // Потокове введення-виведення
#include <windows.h>
using namespace std; // Використання стандартного простору імен
int main()
{
char str[80];
cout << "Enter a string= ";
cin >> str; // Зчитуємо рядок з клавіатури.
cout << "Input string= ";
cout << str;
system("pause");
return 0;
}
Компілюємо програму і бачимо результат.
Результат
Механізм використання функції strcmp()
Звернення до функції strcmp() має такий формат:
strcmp(s1, s2);
Функція strcmp() порівнює рядок s2 з рядком s1 і повертає значення 0, якщо вони однакові.
Якщо рядок s1 лексикографічно (тобто відповідно до алфавітного порядку) більший від рядка s2, то повертається позитивне число.
Якщо рядок s1 лексикографічно менший від рядка s2, то повертається негативне число.
Використання функції strcpy() продемонстровано у наведеному нижче коді програми, яка слугує для перевірки правильності пароля, введеного користувачем.
Завдання 6
Продемонструємо використання функції strcmp() для порівняння рядків.
Текст програми:
#include <iostream> // Потокове введення-виведення
#include <windows.h>
using namespace std; // Використання стандартного простору імен
void main()
{
char str[80];
cout << "Enter a password: "; gets(str);
if(strcmp(str, "qqq")) // Рядки різні.
{
cout << "Password invalid. Access denied" << endl;
}
else
{
cout << "The passcode is valid " << endl;
}
system("pause");
}
Компілюємо програму і бачимо результат.
Результат
У процесі виконання наведеної нижче програми запит вхідних даних продовжується доти, доки користувач не введе слово "Exit".
Завдання 7
Продемонструємо використання функції strcmp() для порівняння рядків.
Текст програми:
#include <iostream> // Потокове введення-виведення
#include <windows.h>
using namespace std; // Використання стандартного простору імен
int main()
{
char str[80];
for(;;)
{
cout << "Enter a string= "; gets(str);
if(!strcmp("Exit", str)) break;
}
system("pause");
}
Компілюємо програму і бачимо результат.
Результат
Механізм використання функції strlen()
Загальний формат виклику функції strlen() є таким:
strlen(s);
У цьому записі s – рядок. Функція strlen() повертає довжину рядка, вказаного аргументом s. У процесі виконання наведеної нижче програми буде показано довжину рядка, введеного з клавіатури.
Завдання 8
Продемонструємо використання функції strlen() для визначення довжини рядка.
Текст програми:
#include <iostream> // Потокове введення-виведення
#include <windows.h>
using namespace std; // Використання стандартного простору імен
int main()
{
char str[80];
cout << "Enter a string: "; gets(str);
cout << "The string length is: " << strlen(str);
system("pause");
}
Компілюємо програму і бачимо результат.
Результат
Якщо користувач введе рядок "Good day", програма виведе на екрані число 8. При підрахунку символів, з яких складається заданий рядок, ознака завершення рядка (нульовий символ) не враховується.
А у процесі виконання цієї програми рядок, введений з клавіатури, буде відображено на екрані в зворотному порядку. Наприклад, під час введення слова "привіт" програма відобразить слово тівирп. Необхідно пам'ятати, що рядки є символьні масиви, які дають змогу посилатися на кожен елемент (символ) окремо.
Завдання 9
Продемонструємо використання рядка як символьного масиву, який дає змогу посилатися на кожен елемент (символ) окремо.
Текст програми:
#include <iostream> // Потокове введення-виведення
#include <windows.h>
using namespace std; // Використання стандартного простору імен
void main()
{
char str[80];
cout << "Enter a string: "; gets(str);
for(int i=strlen(str)-1; i>=0; i--) cout << str[i];
system("pause");
}
Компілюємо програму і бачимо результат.
Результат
У наведеному нижче прикладі продемонструємо використання всіх розглянутих вище чотирьох рядкових функцій.
Завдання 10
Продемонструємо використання всіх розглянутих вище чотирьох рядкових функцій.
Текст програми:
#include <iostream> // Потокове введення-виведення
#include <windows.h>
using namespace std; // Використання стандартного простору імен
void main()
{
char s1[80], s2[80];
cout << "Enter two lines: "; gets(s1); gets(s2);
// Визначення довжини рядка
cout << "Their length is equal: " << strlen(s1);
cout << " " << strlen(s2) << endl;
if(!strcmp(s1, s2)) // Порівняння рядків
cout << "Their length is equal" << endl;
else
cout << "Strings are not the same" << endl;
strcat(s1, s2); // Об'єднання рядків
cout << s1 << endl;
strcpy(s1, s2); // Копіювання рядка
cout << s1 << " and " << s2 << " ";
cout << "now the same" << endl;
system("pause");
}
Якщо запустити цю програму на виконання і на пропозицію ввести рядки "Good" і "day", то вона відобразить на екрані такі результати:
Their length is equal: 4 3
Strings are not the same
Goodday
day and day now the same
Компілюємо програму і бачимо результат.
Результат
Останнє нагадування: не забувайте, що функція strcmp() повертає значення false, якщо рядки однакові. Тому, якщо Ви перевіряєте рівність рядків, необхідно використовувати оператор "!" (НЕ), щоб реверсувати умову (тобто змінити її на зворотне), як було показано в попередній програмі.
Механізм використання ознаки завершення рядка
Факт завершення нульовими символами всіх С++-рядків можна використовувати для спрощення різних операцій над ними. Наведений нижче приклад дає змогу переконатися у тому, наскільки простий програмний код потрібен для заміни всіх символів рядка їх прописними еквівалентами.
Завдання 11
Продемонструємо використання рядка як символьного масиву, який дає змогу посилатися на кожен елемент (символ) окремо для заміни всіх символів рядка їх прописними еквівалентами.
Текст програми:
#include <iostream> // Потокове введення-виведення
#include <cctype> // Робота з символьними аргументами
#include <windows.h>
using namespace std; // Використання стандартного простору імен
void main()
{
char str[80];
int i;
strcpy(str, "test");
for(i=0; str[i]; i++) str[i] = toupper(str[i]);
cout << str;
system("pause");
}
Компілюємо програму і бачимо результат.
Результат
Ця програма у процесі виконання виведе на екран слово TEST. Тут використовується бібліотечна функція toupper(), яка повертає прописний еквівалент свого символьного аргументу. Для виклику функції toupper() необхідно приєднати до програми заголовок <cctype>.
Зверніть увагу на те, що як умову завершення циклу for використано масив str, індексований змінній i, що керує (str[i]). Такий спосіб керування циклом цілком прийнятний, оскільки за дійсне значення у мові програмування C++ приймається будь-яке ненульове значення. Згадаймо, що всі друкарські символи представляються значеннями, не дорівнюють нулю, і тільки символ, що завершує рядок, дорівнює нулю. Отже, цей цикл працює доти, доки індекс не вкаже на нульову ознаку кінця рядка, тобто доки значення str[i] не стане нульовим. Оскільки нульовий символ відзначає кінець рядка, цикл зупиняється точно там, де потрібно. При подальшій роботі з цим навчальним посібником Ви побачите багато прикладів, у яких нульова ознака кінця рядка використовують так само.
Заповнення рядка
Strset() заповнює рядок заданим символом.
Завдання 12
Продемонструємо використання функції strset() для заповннґ рядку заданим символом.
Текст програми:
#include <iostream> // Потокове введення-виведення
#include <windows.h>
using namespace std; // Використання стандартного простору імен
int main()
{
char s1[10];
strset(s1, 's');
cout << s1 << endl;
system("pause");
}
Компілюємо програму і бачимо результат.
Результат
Функції для роботи з рядками
Об'єднання рядків
char* strcat(char* Рядок1, const char* Рядок2);
Поєднує рядки Рядок1 і Рядок2, результат заноситься в рядок Рядок1.
Копіювання рядка
char* strcpy(char *Рядок1, const char *Рядок2);
Копіює вміст рядка Рядок2 у рядок Рядок1, поки не зустрінеться нуль-символ.
char* strncpy(char *Рядок1, const char *Рядок2, n);
Копіює вміст рядка Рядок2 у рядок Рядок1, але не більш n символів.
Визначення довжини рядка
int strlen(const char *Рядок);
Повертає довжину рядка. Нуль-символ при цьому не враховується.
Порівняння рядків
int strcmp(const char *Рядок1, const char *Рядок2);
Виконує посимвольне порівняння рядків (порівнюються коди символів).
Повертає 0, якщо рядки рівні, негативне число, якщо Рядок1<Рядок2 і позитивне число, якщо Рядок1>Рядок2.
Заповнення рядка
char* strset(char *Рядок, char Символ);
Заповнює рядок заданим символом.
Пошук символу в рядку
char* strchr(const char *Рядок,int Символ);
Повертає вказівник на перший знайдений символ або null, якщо символ не знайдений.
#include <stdio.h>
#include <string.h>
int main(void)
{
char *p;
p = strchr("строка из примера", ' ');
printf(p);
return 0;
}
Пошук підрядку в рядку
char* strstr(const char *Рядок1,const char *Рядок2);
Сканує рядок Рядок1 на предмет входження підрядку Рядок2. Повертає вказівник на символ з якого у рядку Рядок1 починається підрядок Рядок2 або null, якщо входження не знайдено.
Примітка – Для використання строкових функцій необхідний заголовний
файл <string.h>.
Приклад
#include <iostream.h>
#include <conio.h>
#include <string.h>
void main()
{
char s1[20];
char s2[15];
char s3[40];
int L1,L2,cm;
char *ch,*st;
clrscr();
//Введення двох рядків
//Примітка - Рядки вводити без пробілів!
cout<<"Ввести рядок s1=";
cin>>s1;
cout<<"Ввести рядок s2=";
cin>>s2;
//Визначення довжини рядків
L1=strlen(s1);
L2=strlen(s2);
cout<<"Довжина рядка s1="<<L1<<endl;
cout<<"Довжина рядка s2="<<L2<<endl;
//Копіювання рядка s1 у s3
strcpy(s3,s1);
cout<<"Рядок s3 після копіювання="<<s3<<endl;
//З'єднання рядків s3 і s2
strcat(s3,s2);
cout<<"Рядок s3 після з'єднання="<<s3<<endl;
//Порівняння рядків s1 і s2
cm=strcmp(s1,s2);
if (cm>0) cout<<"Рядок s1 більше s2"<<endl;
if (cm<0) cout<<"Рядок s2 більше s1"<<endl;
if (cm==0) cout<<"Рядки рівні"<<endl;
//Пошук символу
ch=strchr(s1,'s');
if (ch) cout<<"Символ s у позиції="<<ch-s1<<endl;
//Пошук підрядка
st=strstr(s1,"sdf");
if (st) cout<<"Підрядок sdf у позиції="<<st-s1<<endl;
}
Особливості введення/виведення рядків і символів
Введення рядка може здійснюватися також як і введення числових даних за допомогою функції scanf() або вхідного потоку cin. Але в цьому випадку будуть зчитуватися тільки символи до першого пробілу. Вирішити цю проблему можна такими способами:
