Лабораторная работа. Обработка строк.




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

При использовании библиотечных функций следует учитывать некоторые особенности их выполнения и представления символьных данных в памяти.

  • Функции, работающие с регистрами, распространяются только на латиницу.
  • В С++ некоторые параметры функций обработки символов принадлежат типу int (unsigned), поэтому, если число станет больше 128 (255), функция будет работать некорректно.
  • Перед первым обращением к строке она должна быть объявлена и проинициализирована. Во многих случаях в качестве начального значения строки необходимо бывает задать пустую строку. Такую инициализацию можно выполнить с помощью вызова функции strcpy(s, "");, но более эффективным будет присваивание*s=0;. Кроме того пустую строку можно инициализировать char s[10]=""; или char s[10]="\0";, но при этом размер строки должен быть задан.
  • Функции копирования (кроме strncpy) не проверяют длину строки. Размер строки-приемника должен быть больше, чем размер источника на 1 символ (для символа '\0').

При вызове функции strncpy следует помнить, что, если длина копируемой строки превосходит параметр kol, то строка-получатель не будет завершена символом '\0'. В этом случае такой символ надо дописывать в конец строки вручную.

Функции для работы со строками – файл stdlib.h
Функция Прототип Краткое описание действий
atof double atof (const char *str); преобразует строку str в вещественное число типа double
atoi int atoi (const char *str); преобразует строку str в целое число типа int
atol long atol (const char *str); преобразует строку str в целое число типа long
itoa char *itoa (int v, char *str, int baz); преобразует целое v в строку str. При изображении числа используется основание baz (2 baz 36). Для отрицательного числа иbaz =10 первый символ "минус" (–).
ltoa char *ltoa (long v, char *str, int baz); преобразует длинное целое v в строку str. При изображе-нии числа используется основание baz (2 baz 36).
ultoa char *ultoa (unsigned long v, char *str, int baz); преобразует беззнаковое длинное целое v в строку str
Функции для работы со строками – файл string.h
Функция Прототип Краткое описание действий
strcat char *strcat (char *sp, const char *si); приписывает строку si к строке sp (конкатенация строк)
strchr char *strchr (const char *str, int c); ищет в строке str первое вхождение символа с
strcmp int strcmp (const char *str1, const char *str2); сравнивает строки str1 и str2. Результат отрицателен, если str1<str2; равен нулю, если str1==str2, и положителен, если str1>str2(сравнение беззнаковое)
strcpy char *strcpy (char *sp, const char *si); копирует байты строки si в строку sp
strcspn int strcspn (const char *str1, const char *str2); определяет длину первого сегмента строки str1, содержащего символы, не входящие во множество символов строки str2
strdup char *strdup (const char *str); выделяет память и переносит в нее копию строки str
strlen unsigned strlen (const char *str); вычисляет длину строки str
strlwr char *strlwr (char *str); преобразует буквы верхнего регистра в строке в соответствующие буквы нижнего регистра
strncat char *strncat (char *sp, const char *si, int kol); приписывает kol символов строки si к строке sp (конкатенация)
strncmp int strncmp (const char *str1, const char *str2, int kol); сравнивает части строк str1 и str2, причем рассматриваются первые kol символов. Результат отрицателен, если str1<str2; равен нулю, если str1==str2, и положителен, если str1>str2
strncpy char *strncpy (char *sp, const char *si, int kol); копирует kol символов строки si в строку sp ("хвост" отбрасывается или дополняется пробелами)
strnicmp int strnicmp (char *str1, const char *str2, int kol); сравнивает не более kol символов строки str1 и строки str2, не делая различия регистров (см. функцию strncmp)
strnset char *strnset (char *str, int c, int kol); аменяет первые kol символов строки str символом c
strpbrk char *strpbrk (const char *str1, const char *str2); ищет в строке str1 первое появление любого из множества символов, входящих в строку str2
strrchr char *strrchr (const char *str, int c); ищет в строке str последнее вхождение символа с
strset char *strset (char *str, int c); заполняет строку str заданным символом c
strspn int strspn (const char *str1, const char *str2); определяет длину первого сегмента строки str1, содержащего только символы, из множества символов строки str2
strstr char *strstr (const char *str1, const char *str2); ищет в строке str1 подстроку str2. Возвращает указатель на тот элемент в строке str1, с которого начинается подстрока str2
strtod double strtor (const char *str, char **endptr); преобразует символьную константу str в число двойной точности. Если endptr не равен NULL, то *endptr возвращается как указатель на символ, при достижении которого прекращено чтение строки str
strtok char *strtok (char *str1, const char *str2); ищет в строке str1 лексемы, выделенные символами из второй строки
strtol long strtol (const char *str, char **endptr, int baz); преобразует символьную константу str к значению "длинное число" с основанием baz (2 baz 36). Если endptr не равен NULL, то*endptr возвращается как указатель на символ, при достижении которого прекращено чтение строки str
strupr char *strupr (char *str); преобразует буквы нижнего регистра в строке str в буквы верхнего регистра
         

Сравнение строк с помощью функции strcmp осуществляется побайтово в лексикографическом порядке, то есть в порядке следования соответствующих байтов строк в таблице кодировки. Именно поэтому значения элементов в строках зависят от регистра.

При использовании библиотечных функций следует иметь в виду, что указатель на строку и имя массива символов указывают на адрес размещения строки в памяти. Это означает, что изменения значений элементов строки сохраняются после завершения работы функции. Чтобы не допустить изменений в строке используется указатель на константу, который не позволит модифицировать данные, хранящиеся по адресуемой области памяти.

Пример 1.

//Программа демонстрирует работу функций из файла string.h

#include "stdafx.h"

#include <iostream>

using namespace std;

int _tmain(int argc, _TCHAR* argv[]){

char st[50],sp[100],str[]="",

si[]="qwerty",

sl[]="qwerty",

sw[]="qwertyu";

int len=0, sravn1, sravn2, sravn3, kol=5;

printf("Введите строку: ");

gets(st);

len=strlen(st); printf("Длина строки = %d\n",len);

printf("Конкатенация строк: %s\n",strcat(st,"12cdb"));

sravn1=strcmp(si,sl);

printf("Сравнение строк: %s==%s результат %d\n",

si,sl,sravn1);

sravn2=strcmp(si,sw);

printf("Сравнение строк: %s<%s результат %d\n",

si,sw,sravn2);

sravn3=strcmp(sw,si);

printf("Сравнение строк: %s>%s результат %d\n",

sw,si,sravn3);

printf("Копирование байтов: %s\n",strcpy(sp,st));

printf("Преобразование букв нижнего регистра в верхний: %s\n",

strupr(st));

printf("Преобразование букв верхнего регистра в нижний: %s\n",

strlwr(st));

printf("Копирование %d символов в другую строку: %s\n",

kol,strncpy(str,st,kol));

printf("Поиск в строке первого появления символа из другой строки:

%s\n",strpbrk(st,si));

printf("Поиск в строке последнее вхождение заданного

символа: %s\n",strrchr(st,'t'));

system("pause");

return 0;

}

Пример 2.

/*Удаление лишних левых и внутренних пробелов в строке при выводе*/

#include "stdafx.h"

#include <iostream>

using namespace std;

int _tmain(int argc, _TCHAR* argv[]){

char st[80];

int i=0,len;

printf("Введите строку: ");

gets(st);

len=strlen(st);//длина строки

printf("Преобразованная строка: ");

//Удалены лишние пробелы слева

while (st[i++]==' ');

//Удалены лишние пробелы внутри строки

for (--i;i<len;i++)

if ((st[i]!=' ')||(st[i+1]!=' '))

printf("%c",st[i]); //если рядом два пробела

system("pause");

return 0;

}

Ключевые термины

Конкатенация строк – это результат последовательного соединения строк.

Лексикографический порядок – правило сравнения символов, основанное на величине кода внутреннего представления каждого символа.

Пустая строка – это строка единичной длины, содержащая только символ конца строки.

Сравнение строк – это результат проверки выполнения отношения "больше", "меньше" или "равно" над строками.

Краткие итоги

  1. Для работы со строками в языке С++ предусмотрены стандартные функции, прототипы которых включены в стандартные библиотеки stdlib.h и string.h.
  2. При обращении к функциям для работы со строками следует учитывать, что изменение значений элементов строк сохраняются после завершения работы функции.
  3. Перед использованием строки в программном коде ее необходимо проинициализировать. Неинициализированные строки могут привести к некорректной работе программы.
  4. В некоторых стандартных функциях по работе со строками следует проводить контроль длин параметров.
  5. Результат работы некоторых функций требует принудительного добавления к строке символа конца строки.
  6. Значения элементов строк зависят от регистра.
  7. Изменение регистра символов кириллицы в программе может выполняться некорректно.

Строки и указатели

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

Так как все строки в языке С++ заканчиваются нулевым символом, который имеет значение <ложь>, то условие в операторе while(*str) будет истинным до тех пор, пока программа не достигнет конца строки.

При разработке функций для работы со строками в большинстве случаев целесообразно применять указатели. Приведем примеры фрагментов программ:

/*Пример пользовательской функции копирования строки s2 в s1*/

char * strcpy_my (char *s1, char *s2){

char *ptrs1 = s1;

//указатель инициализирован на начало строки

while ((*s1++ = *s2++)!= 0);

return ptrs1; //возвращается указатель на строку s1

}

Следующий пример демонстрирует, что использование нулевого ограничителя упрощает различные операции над строками.

/*Пример пользовательской функции конкатенации*/

char * strcat_my (char *s1, char *s2) {

char *p1, *p2;

p1 = s1; p2 = s2;

while (*p1!= '\0') p1++; //найти конец 1-ой строки.

//или while (*p1) p1++;

while ((*p1 = *p2)!= 0) {

/*копировать строку р2, пока не будет скопирован нулевой

Ограничитель*/

p1++;

p2++; //Передвинуть указатели к следующему байту

} //или while ((*p1++ = *p2++)!= 0);/*.

return s1;

}

Пример 1.

/*Демонстрация работы с указателями и с функциями для обработки строк*/

#include "stdafx.h"

#include <iostream>

using namespace std;

int _tmain(int argc, _TCHAR* argv[]){

char string[100], temp[100], *result, simvol;

int numresult, res;

/*создает строку "computer program" посредством

использования strcpy и strcat*/

strcpy(string, "computer");

result = strcat(string," program");

printf("1) создали строку\n%s\n",result);

/*находит строку, в которой первый раз обнаружено 'a'*/

simvol='a';

result = strchr(string,simvol);

printf("2) находим в строке первое вхождение символа \'%c\'\n

%s\n",simvol,result);

/* создает копию строки */

result = strcpy(temp,string);

printf("3) создали копию строку\n%s\n",result);

/* находит "a","b","c" в строке */

strcpy(string,"xyzabbc");

res = strcspn(string,"abc");

printf("4) определяем длину заданного сегмента \n%d\n",res);

/*создает новый указатель на строку для дублирования

строки*/

result = strdup(string);

printf("5) создали новый указатель на строку \n%s\n",result);

system("pause");

return 0;

}

В предыдущих примерах рассматривалось присваивание указателю адреса только первого элемента символьного массива. Однако это можно делать и с адресом любого отдельного элемента массива путем добавления символа '&' к индексированному имени. Особенно удобно пользоваться этим правилом при выделении подстроки. Например, следующая программа выводит на экран часть введенной строки после первого пробела:

Пример 2.

/*Вывести на экран часть строки после первого пробела*/

#include "stdafx.h"

#include <iostream>

using namespace std;

int _tmain(int argc, _TCHAR* argv[]){

char s[80], *p;

int i;

printf("ввести строку: ");

gets(s);

/*найти первый пробел или конец строки*/

for(i=0; s[i] && s[i]!=' '; i++);

p = &s[i];

printf(p);

system("pause");

return 0;

}

В этой программе p будет указывать либо на пробел, если он есть, либо на ноль, если в строке нет пробелов. Если p указывает на пробел, то программа выведет на экран его и затем остаток строки. Например, если ввести фразу <язык программирования С++>, функция printf() напечатает сначала пробел и затем <программирования С++>. Если p укажет на ноль, то на экран ничего не выводится.

Пример 3:

//Выводит каждое отдельное слово и подсчитывает его длину

#include "stdafx.h"

#include <iostream>

using namespace std;

int _tmain(int argc, _TCHAR* argv[]){

char text[100],*p, *razd=".,";

int dlina;

puts ("Введите текст ");

gets(text);

p=strtok(text,razd); // Выделение первого слова текста

while (p) { // Пока можно выделить слово

dlina=strlen(p); // Определение длины слова

cout << "\n слово "<< p << " длина = " << dlina <<"\n";

p=strtok(NULL,razd);

//Выделение второго, третьего, и т.д. слов

}

system("pause");

return 0;

}

При использовании строк или указателей на строки в качестве параметров функций следует учитывать некоторые особенности.

При передаче строки как параметра функции не указывается длина, так как ограничителем является символ конца строки.

Строки передаются в функции в качестве параметров как массивы символов или как указатели типа char.

При побайтовом копировании строки или ее подстроки без использования стандартных функций формируемую строку следует завершить, дописав символ конца строки. В противном случае строка не воспринимается как единое целое, а при выходе за ее границы доступными становятся байты, содержащие "мусор", то есть непредсказуемую информацию.

Обращение к строкам через указатели позволяет вносить и сохранять изменения, записанные в адресуемой области памяти. Для недопущения изменений в строке указатель на константу можно объявить с лексемой const следующим образом: const char *p;.

В силу специфики представления строк в виде символьного массива сами строки, строковые константы, заключенные в кавычки, и указатели на строки обрабатываются эквивалентно. При этом каждый такой элемент адресует область памяти и передается в функции как адрес.

При копировании строки или подстроки с использованием указателя не создается физической копии значений элементов. Объявленный новый указатель адресует то место в памяти, с которого начинается копируемая строка или подстрока. Например:

char text[50]="Язык программирования";

char *p=text, *pp;

//объявление и инициализация указателя р адресом строки text

pp=p;

//указатель рр адресует ту же строку text

Адресация на тот же участок памяти объясняется, во-первых, неэффективностью повторного хранения уже имеющихся данных, во-вторых, относительной программной трудоемкостью копирования байтов, в-третьих, для хранения адреса строки требуется гораздо меньше места, чем для самой строки. В данном контексте понятие эффективности носит относительный характер, так как иногда в программе полезным бывает хранение резервной копии введенных данных.

Ключевые термины

Адрес строки – это указатель на блок непрерывной области памяти, с которого начинает располагаться массив символов.

Строки как параметры функций – это описание передачи значений строк в функции как массив символов или указатель типа char.

Указатель на строку – адрес начала расположения строки в памяти.

Краткие итоги

  1. В силу специфики представления строк в виде символьного массива сами строки, строковые константы, заключенные в кавычки, и указатели на строки обрабатываются эквивалентно.
  2. Строки передаются в функции в качестве параметров как массивы символов или как указатели типа char.
  3. Обращение к конкретному элементу строки можно осуществить посредством адресации индексированного имени строки.
  4. При формировании строки без использования стандартных функций требуется дописывать символ конца строки.
  5. С помощью указателей на константы можно защитить строку от изменений.
  6. Копирование строк с помощью указателей осуществляется через объявление нового указателя, адресующего область памяти, занимаемую строкой или подстрокой.

Выполните приведенные ниже задания.

  1. Дана строка, в которой слова разделены одним пробелом. Найдите и распечатайте все слова указанной длины n.
  2. Дана строка из символов латинского алфавита. Вставьте пробел перед каждой заглавной буквой. Перед первой буквой пробел добавлять не надо. Ниже представлен рекомендуемый вид диалога во время работы программы. Данные, вводимые пользователем, выделены жирным шрифтом.
  3. Дана строка. Проверьте правильность расстановки в ней круглых скобок: каждой открытой скобке должна соответствовать корректно закрытая скобка.
  4. Найдите в строке самый часто встречающийся символ. Распечатайте символ и число его повторений.

Контрольные вопросы

  1. Почему обращения к строке через ее имя и через указатель эквивалентны?
  2. Почему в качестве параметра функции передается адрес строки, а не сама строка символов?
  3. Возможно ли применение операций инкремента и декремента к указателю на строку? Если да, то что будет адресовать полученный указатель?
  4. Почему при формировании строки без использования стандартных функций необходимо дописывать символ конца строки? Почему этого не требуется при считывании строк с клавиатуры?
  5. Какие возможны ошибки в программе при некорректной работе со строками?
  6. Что будет являться результатом работы функции побайтового копирования строк, если длина строки-источника превосходит допустимый размер строки-приемника?
  7. Что будет являться результатом работы функции побайтового копирования строк, если длина строки-источника меньше размера строки-приемника?
  8. Почему при сравнении строк важен регистр символов?
  9. Как сравниваются строки разной длины?

 



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2022-11-27 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: