- •Рядки, дії з рядками
- •Рядки
- •Рядки
- •Рядки
- •Рядки
- •Рядки
- •Рядки
- •Рядки.
- •Рядки
- •Рядки і вказівники
- •Рядки.
- •Рядки.
- •Рядки.
- •Рядки.
- •Рядки.
- •Рядки. Введення-виведення рядків
- •Строки
- •Рядки.
- •Рядки.
- •Рядки.
- •Рядки.
- •Рядки.
- •Рядки.
- •Рядки.
- •Рядки.
- •Рядки.
- •Рядки.
- •Рядки.
- •Рядки.
- •Рядки.
- •Рядки.
- •Рядки.
- •Рядки.
- •Рядки.
- •Рядки.
- •Рядки.
- •Рядки.
- •Рядки.
- •Рядки.
- •Рядки.
Рядки, дії з рядками
Лекція
Рядки
У С + + відсутній спеціальний строковий тип.
У С + + використовуються два види рядків:
рядок як масив символів типу char (char *-рядка)
рядок як об'єкт класу string
рядок як масив символів типу char:
const int MAX = 80; |
// розмір рядка |
char str [MAX]; |
// сам рядок, її визначення схоже на визначення масиву типу char |
cin >> str; |
// введення рядка, наприклад, вводимо рядок “Minsk” |
Останнім символом рядка (як масиву елементів типу char) Обов'язково повинен бути '\ 0' (нуль-символ), тому до довжини масиву завжди необхідно додавати 1.
У пам'яті: |
M i |
n |
s |
k |
\0 |
… |
|
|
|
|
|||
|
строковий буфер str |
|
невикористовувана частина строкового буфера |
|||
|
|
|
|
|
|
|
2
Рядки |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Приклади |
|
|
|
|
|
|
|
|
|
|
|
|
|
«Сміття» |
|
|
|
|
||
char str |
[20] = “Good Morning”; |
|
|
|
|
|
|
|
|
|
||||||||||
|
|
|
|
|
|
|
|
|
|
|
||||||||||
cout << str; |
// Good Morning |
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||
G o o d |
|
M o r n i n g \0 |
|
|
|
|
|
|
|
|
||||||||||
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
|
strcpy(str, “Hello”); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||
cout << str; // Hello |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||
H |
e l l |
o \0 |
o r n i |
n |
g |
\0 |
|
|
|
|
|
|
|
|
||||||
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
|
strcpy(str,“”); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
\0 |
e l l |
o \0 |
o r n i |
n |
g |
\0 |
|
|
|
|
|
|
|
|
||||||
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
Рядки |
|
|
Як і інші типи даних, |
Строкові константи |
|||
|
|
|
рядки можуть бути: |
|
|
||
|
|
|
змінними і константами |
|
|
|
|
У строковий літерал можна включати недруковані символи :
”abc\ndef” // символи будуть надруковані в два рядка ”abc\\ndef” //буде видано abc\ndef
Довгий строковий літерал передбачає запис :
”abc\ def”
рядка
але!!! |
”abc<enter> |
// error!!! |
|
def” |
Рядок "abc \ 000def" буде оброблятися як abc ('\ 0' - означає кінець рядка).
У строковому літералі можливе використання кількох рядків :
"текст1""текст2""текст3";
cout << "abc\\ndef" "aaa" "mmm"<< endl;
виведе рядок abc\ndefaaammm.
#define OTVET1 "odin" |
// препроцесорний рядок-константа |
const char str[3] ="dwa"; |
// типізований рядок-константа |
|
|
Рядки |
|
Визначення рядків : |
|
|
|
|
|
||
1. рядок як масив символів: |
|
|
|
|
// 0-символ додається автоматично |
|
|||
char string [ ] = “Minsk”; |
|
|||
char string1 [6] = “Minsk”; |
// 0-символ додається автоматично |
|
||
char string2 [6] = {‘M’, ‘i’, ‘n’, ‘s’, ‘k’, ‘\0’}; //0-символ додаємо самостійно |
|
|||
cout << sizeof (string1) << endl; |
|
//розмір рядка дорівнює 6 |
cout << strlen (string1) << endl; // довжина рядка дорівнює 5, прототип функції в <string.h>
Ім'я рядка (як і для будь-яких інших масивів) - константних покажчик на неконстантние дані (на елемент з номером 0); тобто ім'я рядка завжди вказує на одну і ту ж комірку пам'яті, але використовуючи
це ім'я і індекси можна звертатися до всіх даних у рядку і змінювати їх: string [i] = * (string + i).
Відмінність від масивів! :
при виведенні покажчик автоматично разименовивается, і ми отримуємо рядок, що починається з елемента номер 0 і що закінчується 0-символом:
cout << string << endl;
cout << & string << endl; / / виводить адресу
Константні покажчики (покажчики, оголошені як const: int * const pi) повинні отримувати початкові значення при своєму визначенні.
string1++; неможно!!! |
покажчик-константа |
pi++ неможно!!! |
string1 [i] = 5; //можно!!! |
дані неконстантні |
pi[2]=3; можно!!! |
Рядки |
Визначення рядків : |
|
2. рядок як вказівник на char:
char *string4 = “Minsk”, *string5; |
// ініціалізація вказівника string4 |
string5 = “design”; |
// ініціалізація вказівника string5 |
У цьому випадку імена рядків - неконстантні вказівники на константні дані: тобто дані «тільки для читання».
char *s1= “pointer_of_simvol”;
//s1[3]='q'; !!!error, спроба змінити константні дані
s1++; |
// OK!!! |
|
cout << s1; |
// ointer_of_simvol |
Хороший стиль – оголошувати сonst char *string4 = “Minsk”;
Неконстантні вказівники string4 і string5 отримують початкові значення, рівні адресами перших елементів строкових літералів. Самі літерали у форматі С- рядки розташовуються в пам'яті програми.
Покажчик на char автоматично разіменовивається як і для рядка-масиву. В якості негативних наслідків :
char c=‘a’; char *pc=&c; cout << pc;
виводить з пам'яті все підряд з адреси символу 'a' і до «випадкового» символу ‘\0’.
!!!cout << sizeof (*string4) << endl; // виведе 1, нульовий елемент рядка cout << strlen (string4) << endl; // виведе 5, без '\ 0', прототип функції в <string.h>// виведе 4, розмір вказівникаcout << sizeof (string4) << endl;
Рядки
3. рядок як елемент масиву рядків
char den[ ][10]= {"poned", "vtor", "sreda", "chetv", "pjatn", "sub", "voskr"};
4. рядок як елемент масиву покажчиків на char char *otvet1[ ] = { ”odin”, “dwa” };
char str1[ ] = "string-array"; |
// рядок-масив: str1-константний вказівник |
|
// на неконстантні дані, ініціалізується літералом |
cout << str1 << endl; |
//виведе: string-array |
// str1++; |
// ні, str1 – вказівник-константа |
str1[0]='a'; |
// так, str1 – вказівник на неконстантні дані |
cout << str1[0]<< endl; |
// виведе перший елемент рядка : a |
char* str2 = "string-pointer"; // рядок-вказівник: str2-неконстантний вказівник
|
// на строкову константу, ініціалізується її адресою |
cout << str2 << endl; |
//виведе: string- pointer |
str2++; |
// да, str2 – вказівник-змінна |
// str2[1]='a'; |
// нет, str2 – вказівник на константу |
cout << str2<< endl; |
//виведе: tring-pointer |
Для динамічного рядка описуємо вказівник на char і виділяємо пам'ять за
допомогою new или malloc. |
|
|
Динамічні рядки, як і інші |
|
|
char *p = new char[m]; |
|
|
динамічні масиви, не можна |
|
|
char *q = (char *) malloc(m*sizeof(char)); |
ініціалізувати при створенні |
|
|
|
|
Рядки.
Особливості роботи з C-рядками, описаними різними способами
//приклад 1: рядок - вказівник
#include <string.h>
#include <malloc.h> int main ( )
{char *name; // вказівник на символ name = (char*) malloc(10);
printf (“ name?\n“); // OK!!! scanf (“%s”, name); // або cin >> name;
char *name1; // вказівник на символ
name1 = “hello”; // OK!!! printf (“%s %s”, name, name1);
char *name2; // вказівник на символ
printf (“ name?“);
//scanf (“%s”, name2); error!!!
// місце під рядок не виділене
return 0;
}
//пример 2: рядок-масив |
|
int main ( ) { |
|
char name3 [10]; |
// рядок-масив |
printf (“ name?“); |
// OK!!! |
scanf (“%s”, name3); //або cin >> name3;
char name4[10]; // рядок-масив strcpy (name4, “hello”); // OK!!! printf (“%s %s\n”, name3, name4);
char name5[10]; // рядок-масив
// name5 = “привіт”; error!!!
}// спроба змінити адресу рядка
char *string = ”Minsk”; char *string1 = ”Minsk”;
// рядки ініціалізуються однією адресою
8
Рядки
Особливості роботи з С-рядками
•для представлення с - рядків використовуються масиви елементів типу char, що містять в кінці послідовності значущих символів код '\ 0 ‘
• с -рядок обмежена розміром масиву , який виділений для її подання; розмір недінаміческой з -рядки повинен бути заданий тільки константним виразом;
•строка може бути проініціалізувати як поелементно символьними значеннями, так і значенням строкового літерала , причому завершальний символ '\ 0 ' формується в цьому випадку в кінці рядка автоматично;
•нульова рядок - це рядок , яка починається з 0 -символа '\ 0 ' (її довжина дорівнює нулю , але в пам'яті вона може займати більше одного байта ) ; нульовий вказівник на рядок ( char * p_str = NULL ;) не є еквівалентом нульової рядки;
•поточна довжина рядка відстежується в процесі виконання дій над рядком;
•при розміщенні у вихідний потік cout імені символьного масиву виводиться не адреса масиву (як для масивів з елементами іншого типу) , а його вміст (до завершального символу '\ 0 ');
•для роботи з с- рядками використовуються бібліотечні функції мови С, описані в заголовках <string.h> і < сstring > , однак треба враховувати , що в цих функціях немає контролю за кордонами рядків.
Рядки і вказівники
s
a b c d \0
typedef char ar_char [5];
ar_char s ="abcd"; cout << s << endl; // abcd char *pchar = NULL;
pchar =s; cout << pchar << endl;
cout << |
*pchar << endl; |
// a |
cout << |
*(pchar +2); |
// c |
pchar
0
// abcd |
parchar =&s |
|
|
parchar |
|
ar_char *parchar = NULL; |
0 |
|
|
|
|
|
|||
// parchar =s; |
error!!!, convert from 'ar_char' to 'ar_char (*) ' |
|||
// pchar =&s; |
error!!! |
|
|
|
parchar =&s; |
// ok!!! |
|
|
|
cout<< parchar << endl; |
// адреса рядка-масиву |
|||
cout << * parchar << endl; |
// abcd рядок-масив |
cout << ** parchar << endl; // a перший символ рядка-масиву
Слайд не для всех!!!