ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 22.12.2021

Просмотров: 130

Скачиваний: 2

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

Лекція 6

Рядки. Рядкові змінні

Відомо, що рядки це послідовність символів, які визначаються за допомогою коду ASCIІ, як в мові Паскаль.

Рядкова змінна – це така змінна, що може зберігати послідовність символів, подібно рядку на якому надруковані різні літери або інші символи. Обробка рядкових змінних в Сі має непростий характер, наприклад, в мові Visual Basic це робити зручніше. Рядкова змінна називається змінною- масивом типа char.

Символьним змінним можна присвоювати початкові значення. Це можливо зробити прямо в операторі оголошення. В дійсності можна не вказувати довжину рядка. Далі написані три оператора є еквівалентними:


char Radock [4]= {'c', 'a', 't', '\0'};

char Radock [4]= “cat”;

char Radock [ ]= “cat”;

Якщо текст записується в подвійні лапки, Сі розглядає його як рядок; це означає, що компілятор автоматично добавляє в кінець рядка нульовий символ. В першому прикладі його добавляють явним чином. Якщо в оголошенні рядка пропускається значення індекса, Сі підраховує, скільки символів в літерному рядку, добавляє одиницю, щоб врахувати нулевий символ, і створює рядок-змінну, яка точно відповідає ініційованому тексту. Якщо написати

char Mas [5]= “Україна”;

то це буде помилка, тому що змінна має менший розмір, чим їй присвоюється. Якщо забрати 5, то буде створено рядок потрібної довжини.

Щоб працювати з рядками, потрібно в свої програми включати заголовочні файли, такі, як string.h та stdio.h.

Розглянемо три простих дії над рядками.

Перша: Це знайома нам операція конкатенації, або склеювання рядків. Виконати конкатенацію рядків – це означає взяти другий з них і приставити його в кінець першого рядка; утвориться новий рядок, що є добутком двох рядків.

Для цього використовується функція strcat:

{ char Name [15]= “Igor”;

char NN [ ]= “Ivanov”;

strcat (Name; NN)’;

puts (Name);

}

Рядок, в який записується результат повиннен бути достатньо довгим, щоб вмістити обидва рядки, інакше виникне помилка.

Друга: Функція strcpy ( ) – копіювання рядка: на другому місці на місто першого, вилучаючи значення попереднього:

strcpy (st1, st2 );

Рядок st1 повинен бути більшим за st2.

Третя: Для того, щоб знайти точний розмір рядка використовують функцію strlen ( ).

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

Функцію можна використовувати в оператрі присвоювання:

Length = strlen (st1);

Для введення рядків використовуйте функцію gets ( ). Цю функцію можна використовувати і для того, щоб звільнити буфер клавіатури після формального введення. Іноді в буфері залишаються невикористані символи; наступна функція може їх використати, із-за чого буде помилковий результат. Використовуйте оператори типу:

char Trash [80];

gets (Trash);

Для виведення рядка користуйтесь функціями puts(st) і printf (“%s”, st);

Прототипом функції strlen є:

int strlen (char *pointer);


тобто функція чекає, що pointer буде покажчиком на символьну змінну. Звідки функція strlen “знає”, скільки символів у рядку? Вона шукає завершуючий нуль символ \0. Початок рядка передається функції в якості аргумента; це покажчик. (Згадайте, що покажчик містить адресу початку змінної).

В Сі ім’я масиву є константним покажчиком на його перший елемент. Тому що рядки в Сі – масиви символів, ім’я рядка є покажчиком на початок рядка.

Нульовий символ є важливим моментом. Якщо ви напишите програму, яка створює рядок із окремих елементів, не додавши в кінець нульовий символ у вас будуть неприємності. Функції Сі не цікавляться тим, скільки елементів ви дали масиву, який створює рядок при його оголошені. Вони шукають /0. Обшукують пам’ять байт за байтом, поки не зустрінуть нуль. В результаті з пам’яті буде витягнута купа непотрібної інформації.

Існують ще багато функцій для роботи з рядками. Самі поширені це:

strncpy – для копіювання загального числа символів із одного рядка в інший.

puts ( “\n введіть рядок”);

gets ( sour); puts(“Скільки символів копіювати?”);

scanf ( “%d”, &num);

strncpy ( Res, sonr, num);

printf ( “ Перші %d символів: %s”, num, Res);

strcmp () функція порівняння двох рядків.

Її прототип – іnt strcmp ( const *char string1, const *char string2);

- strncmp () – функція порівняння частини рядків.

Її прототип – іnt strcmp ( const *char string1, const *char string2, num);

Повертаєме значення менше нуля, якщо string1 менше ніж string2 (тобто string1 іде за алфавітом раніше ніж string2). Значення дорівнює нулю, якщо рядки співпадають. Значення більше нуля, якщо string2 менше string1. Майте на увазі, шо strcmp () розрізняє регістри і великі букви йдуть за алфавітом раніше маленьких.

- strchr () – пошук одного рядка в іншому.

Її прототип – char *strchr ( const char *string, int char_to_find);

Функція повертає покажчик на знайдений в рядку string символ char_to_find. Якщо такого немає, то повертає нуль. Для визначення позиції символа в рядку треба використовувати арифметику покажчиків. Треба відняти із покажчика, що повертає значення, покажчик на початок рядка; результат буде цілим зміщенням, що відповідає положенню символа.

Пошук першого проміжка:

PLOC=strchr (string, _);

POS= PLOC - string;

strrchr () шукає останнє входження в рядок, подібна попередній;

strcspn () шукає в рядку перше входження будь-якого символа із другого рядка;

strstr () шукає перше входження підрядка, повертає покажчик, тобто char *strstr()

Приклад: 1) Напишіть блок операторів, які знаходять останню кому в рядку.

pPosi=strrchr (Astring, ‘,’);

posi=pPosi-Astring;

2) Напишіть блок операторів, які вивчають рядок на предмет першого входження в неї однієї з десяткових цифр.

strcspn (A string, ’’123456789’’);

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


Рекомендації для обробки рядків

Стисло нагадаємо деякі особливості обробки рядків.

1. Визначення символьного масиву фіксованого розміру:

char Array [25];

Не можна розмір масиву задавати за допомогою змінної, тобто буде помилкою визначення (якщо N – непрепроцесорний ідентифікатор):

char Array [N]

2. Визначення динамічного масиву:

char *p;

int N = 25;

р = (char*) malloc(N);


3. Звернення до елемента масиву:

вирази Аrrау[0] і * Array – еквівалентні. Також еквівалентні вирази:

Array[i] *(Array+i) *(i+Array), i[Array]

Для динамічного масиву, адресованого покажчиком р, еквівалентні вирази:

р[0] *р;

p[i] *(p+i) *(i+p), i[p]

4. Перехід до сусіднього (i+1)-го елементу динамічного масиву:

наступні вирази еквівалентні: p[i+1], p++[i] *(p++ +i)

Невірно: Array++[i] – ім'я масиву є константа, за визначенням її не можна змінювати.


5. Варіанти перебору елементів масиву.

int i ;

for (i = 0; i < 25; i++) {Array[i]. . . }

for (i = 0; i < 25; i++) {* (Array+i) . . . }

for (i = 0; i < 25; i++) {* (p+i) . . . }

for (i = 0; i < 25; i++) {p[i]. . . }

Небезпечний варіант (можна забути початок масиву):

for (i = 0; i < 25; i++)

{ *p++….}


6. Рядки в мові Сі "розміщуються" в символьних масивах. Ознакою закінчення рядка служить '\0'.

Якщо визначено масив char string[25]= "це рядок";

то в масиві string[ ] завдовжки 25 байтів буде розміщений рядок завдовжки в 11 байтів і string[10]= = '\0'.

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

char *ps = "рядок"; /* Довжина рядка 7 байтів;

ps[6] == '\0'; *(ра+6)== '\0' */

char str [ ] = "це рядок"; /* Рядок і масив однакової довжини */


7. Для введення рядків (які набирають на клавіатурі) зручно використовувати функцію char* gets(char* s), яка розміщує введену послідовність символів в область пам'яті, що адресується покажчиком s. При цьому ознака кінця введення '\n', що додається у вхідний потік при натисненні клавіші <Enter>, функція gets( ) замінює ознакою кінця рядка '\0'.

Використання для введення рядків функції scanf("%s"...) не дозволяє вводити послідовність символів, в яких містяться пропуски або узагальнені пробільні символи. Введення за специфікацією %s виконується до найближчого пропуску.


8. Обчислити довжину (len) рядка, що знаходиться в масиві string або що адресується покажчиком char * string; можна так:

int len;

for (len=0; *(*string+len)!='\0'; len ++) ;

Ще більш зручно застосовувати функції для роботи з рядками із стандартної бібліотеки. Вони описані в заголовному файлі string.h. Наприклад, для визначення довжини рядка використовуйте функцію з прототипом unsigned strlen(char *str). (Повертає довжину рядка без урахування символу, що завершує рядок '\0'.)


9. Копіювати рядок з масиву string або з рядка, що адресується покажчиком char * string, в новий масив, що адресується покажчиком char * s, можна таким чином:

int j;

char *s; s = (char *)malloc(len);

for (j=0; j <= len; j++)

*(s+j)=*(string+j);

тут len – довжина початкового рядка.

Варіант, який зміщує покажчик з початку області пам'яті:

char *а; а = (char *)malloc(len5);

for (; *a++=*s++;);



10. Функції з параметрами-рядками:

1) застосування покажчиків

int length (const char *s) /* const – захист від зміни фактичного параметра */

int i;

{ for (i=0; *( s +і)!='\0'; i++)

/* Навіть вираз *(s++) не змінює "настройку" параметра на зовнішній масив */

return i; /* Довжина рядка */

}

2) застосування масиву

int length (char а[ ]) /*а – є const за синтаксисом масива */

{ int i=0;

while (а[i++] != '\0');

return i-1; /* Довжина (рядка)*/

}

Приклад виконання завдання з обробки рядків

Ввести символьний рядок і розділити її на частини фіксованої довжини. Вивести на екран отримані частини рядка "в стовпчик", тобто кожну частину з нового рядка дисплея. Нехай в кожній частині рядка буде не більше трьох символів.

Текст програми:

/* Динамічні символьні масиви, покажчики і рядки */

#include <stdio.h>

#include <string.h>

void main()

{

int LenMax, Len = 0 ;

char *h, *input;

int ks; /* Кількість "частин" рядка */

/* Покажчик на масив покажчиків на частини: */

char **c;

int n = 0 ;

int j = 0;

int i ;

printf ("\n Введіть максимальний розмір рядкa : ");

scanf("%d", &LenMax);

/* Виділити пам'ять для рядка, що вводиться: */

input = (char *)malloc (LenMax);

printf ("\n Введіть рядок:");

/* Видалення символу '\n' з вхідного потоку: */

getchar() ;

/* Читання рядка: */

while ((*(input+Len++)=getchar()) !='\n');

Len --;

/* Len – кількість введених символів */

/* Додати ознаку кінця рядка: */

* (input+Len) =' \0 ';

/* Виділити пам'ять для введеного рядка: */

h=(char *)malloc(Len+1);

/* Копіюємо інформацію з початкового рядка */

while (* (h+j++)=* input++);

/* Видалення з пам'яті початкового рядка: */

free (input);

ks = (Len+2)/3; /* Кількість частин */

c = (char **)calloc (ks, sizeof(char *));

/* Ділення рядка на ks "частин" */

for(j = 0; j < ks; j++)

{ /* Пам'ять для частини: */

*(c+j) = (char *)malloc(4);

for (i = 0; (i < 3 && *(h+n) ); i++)

*(*(c+j) +i)= *(h+ n++);

*(*(c+j)+i)='\0';

}

/* Видалення з пам'яті обробленого рядка: */

free (h);

/* Виведення "частин" початкового рядка */

for (j = 0; j < ks; j++)

{

printf("\n %s", *(c+j) );

}

/* Звільнити пам'ять від динамічних масивів:*/

for (j = 0; j < ks; j++)

free (*(c+j)); free (c);

}

Приклад виконання програми:

Введіть максимальний розмір рядка: 60

Введіть рядок: World_Wide_Web!

Wor

ld_

Wid

e_W

eb!

В програмі необхідно звернути увагу на такі особливості.

Читання символів вхідного потоку виконується двома різними функціями. В циклі (закінченням якого служить поява символу '\ n ') за допомогою getchar( ) читається послідовність символів в область пам'яті, що адресується покажчиком char* input. Перед цим за допомогою функції scanf("%d",&LenMax) прочитується значення LenMax. Тут виникає одна незручність. Функція scanf() при введенні "залишає" у вхідному потоці ознаку '\n' кінця послідовності, що вводиться. Якщо потім йде введення за допомогою функції getchar(), то першим зчитаним значенням буде '\n'. Саме тому перед циклом за допомогою getchar() з вхідного потоку видаляється непотрібний символ '\n'.

Наступна особливість – відсутність індексованих змінних. Для доступу до елементів масивів, в яких розміщуються символи рядків, використовується розіменування покажчиків і виразів з покажчиками, наприклад: *(*(c+j)+i). Як вправа рекомендується написати варіант програми з індексованими змінними для доступу до окремих символів рядків.


Ще одна особливість – відсутність звернень до стандартних функцій для роботи з рядками. Програму можна спростити, якщо використовувати функції для визначення довжини рядків strlen(), для копіювання рядків strcpy() і ін.


Питання для самоконтролю.

  1. Дайте визначення рядка? Який символ в С відмічає кінець рядка?

  2. Що означає термін конкатенація?

  3. Як записується символьна літеральна константа? Рядкова літеральна константа?

  4. Що не пишеться в назві рядка, якщо вона передається якій-небудь функції обробки рядків.

  5. Чому важливо очищувати вхідний буфер після форматного введення?

  6. Напишіть оператор який створює змінну-рядок, яка може містити до 80 символів. Назвіть Line. Char Line[80];

  7. Де знаходяться прототипи функцій обробки рядків?

  8. Яка функція використовується для копіювання перших n символів із одного рядка в інший?

  9. В чому різниця між функціями strchr() i strrchr()?

  10. За допомогою якого ключового слова можна визначити синонім типу?


7