Будьте осторожны при явной инициализации строки. Так, оператор
char *str = “Строковая константа”;
использовать некорректно, так как он создает не строковую переменную, а указатель на строковую константу, изменить которую невозможно.
Динамические строки нельзя инициализировать при создании.
2) интерактивный ввод строки (с использованием различных операторов ввода).
- для ввода строки, состоящей из одного слова (ввод до первого пробельного символа: пробела, знака табуляции, символа перевода строки) используется cin:
const int n = 80;
char s[n];
cin >> s;
- для ввода строки, состоящей из нескольких слов, используются методы getline или get класса istream, объектом которого является cin. Для вызова метода после имени объекта ставится точка, а затем пишется имя метода:
const int n = 80;
char s[n];
cin.getline(s,n); cout << s << endl;
cin.get(s,n); cout << s << endl;
Метод getline считывает из входного потока (n-1) символов или менее (если символ перевода строки встретиться ранее) и записывает их в строковую переменную s. Символ перевода строки (он же ‘\n’, появляется во входном потоке при нажатии клавиши Enter) также сичтывается (удаляется) из входного потока, вместо него размещается завершающий нуль-терминатор.
Метод get работает аналогично, но оставляет в потоке символ перевода строки. В строковую переменную добавляется завершающий нуль-терминатор. Нельзя обращаться к методу get с двумя аргументами два раза подряд, не удалив ‘\n’ из входного потока. Это возможно вызовом метода get без параметров:
cin.get(s,n); cout << s << endl;
cin.get(); // убрали ‘\n’
cin.get(s,n); cout << s << endl;
- для ввода нескольких строк удобно использовать метод getline в заголовке цикла:
const int n = 80;
char s[n];
while (cin.getline(s,n)) {
cout << s << endl;
… }
- для ввода строки (до первого пробельного символа) можно использовать функцию scanf(),задав спецификацию формата ‘%s’:
const int n = 80;
char s[n];
scanf(“%s”, s); printf(“%s”, s);
- чтобы ввести строку из нескольких слов используется спецификация ‘%c’с указанием максимального количества вводимых символов:
scanf(“%80с”, s);
- для ввода строк используются также специальная функция gets():
const int n = 80;
char s[n];
gets(s);
Функция gets(s) читает символы с клавиатуры до появления символа новой строки и помещает их в строку s (сам символ в строку не включается, вместо него в строку заносится нуль-символ). Функция возвращает указатель на строку s, а в случае возникновения ошибки или конца файла – NULL.
Вывод строки на экран.
- для вывода может использоваться команда стандартного (потокового) вывода “<<” библиотеки С++:
const int n = 80;
char s[n];
cin >> s; cout << s << endl;
- при выводе с помощью функции printf(), можно задать количество позиций, отводимых под строку; строка при этом выравнивается по правому краю отведенного поля:
const int n = 80;
char s[n];
scanf(“%s”, s); printf(“%s”, s);
printf(“%80s”, s); // с заданием количества позиций в строке
- функция puts(s) выводит строку s на стандартное устройство вывода, заменяя завершающий нуль-терминатор символом новой строки. Возвращает неотрицательное значение при успехе или EOF (признак конца файла) при ошибке:
const int n = 80;
char s[n];
gets(s); puts(s);
Рассмотрим примеры использования команд ввода-вывода строк в различных компиляторах С++:
1) Использование функций gets() и puts():
Пример 1:
#include "stdafx.h"#include <iostream>using namespace std;int _tmain(int argc, _TCHAR* argv[]){ char s[20]; gets(s); puts(s); system("pause"); return 0;}Результат выполнения программы: при вводе строки "123 456 789" чтение данных осуществляется побайтно до символа '\n', то есть в s занесется строка "123 456 789\0" (управляющая последовательность '\0' на экран не выводится, а является признаком конца строки). При выводе строки функция puts() возвращает в конце строки дополнительно один символ '\n', следовательно, будет выведена строка "123 456 789\n" (управляющая последовательность '\n' на экран не выводится, а осуществляет перевод курсора на новую строку).
Пример 2. Вычислите длину введенной строки.
#include "stdafx.h"#include <iostream>using namespace std;int _tmain(int argc, _TCHAR* argv[]){ char st[100]; int i=0; puts("Введите строку:"); gets(st); while(st[i++]); printf("Длина введенной строки = %i\n",i-1); system("pause"); return 0;2) Использование стандартного ввода-вывода:
Пример 3:
#include "stdafx.h"#include <iostream>using namespace std;int _tmain(int argc, _TCHAR* argv[]){ char s[20]; cin>>s; //ввод строки из стандартного потока cout<<s; //вывод строки в стандартный поток system("pause"); return 0;}Результат выполнения программы: при вводе строки "123 456 789" чтение данных осуществляется побайтно до первого пробела, то есть в s занесется только первое слово строки "123\0", следовательно, выведется: "123".
Пример 4. Введите слово и замените в нем все вхождения заглавной латинской 'A'на малую латинскую 'a'. Выведите слово после редактирования.
#include "stdafx.h"#include <iostream>using namespace std;int _tmain(int argc, _TCHAR* argv[]){ char st[80]; int i; cout << "\nВведите слово: "; cin >> st; for(i=0;st[i]!='\0';i++) if (st[i]=='A') st[i]='a'; cout << "\nСлово после редактирования: "<< st; system("pause"); return 0;}3) Использование форматированного ввода-вывода:
Пример 5:
#include "stdafx.h"#include <iostream>using namespace std;int _tmain(int argc, _TCHAR* argv[]){ char s[20]; scanf("%s",s); //для строк не используется обращение по адресу & printf("%s",s); system("pause"); return 0;}Результат выполнения программы: при вводе строки "123 456 789", чтение данных осуществляется побайтно до первого пробела, то есть в строку s занесется только первое слово строки "123\0", следовательно, выведется: "123". Так как s– имя символьного массива, то есть адрес его начального элемента, операция & в функции scanf для строк не используется.
Пример 6. Записать введенную строку символов в обратном порядке.
#include "stdafx.h"#include <iostream>using namespace std;int _tmain(int argc, _TCHAR* argv[]){ char st[80]; char temp; int i,len=0; printf("\nВведите строку > "); scanf("%s",st); while (st[len++]); //вычисление длины строки len-=2;//поправка на символ конца строки и нумерацию с нуля for(i=0;i<len;i++,len--){ temp=st[i]; //обмен символов st[i]=st[len]; st[len]=temp; } printf("\nПолученная строка > %s",st); system("pause"); return 0;}Обработка строк.
Осуществляется с помощью функций. Для работы со строками используются библиотечные функции, прототипы которых находятся в заголовочных файлах stdlib.h и string.h.
В программах, в зависимости от типа, вызовы функций для работы со строками задаются в виде:
ИмяФ(СписокАргументов);или
ИмяПерем=ИмяФ(СписокАргументов);где ИмяФ – имя функции;
СписокАргументов – список аргументов, передаваемых в тело функции;
ИмяПерем – идентификатор соответствующего типа.
Например:
y=strlen(st); /*переменной y присвоить значение длины строки st*/При использовании библиотечных функций следует учитывать некоторые особенности их выполнения и представления символьных данных в памяти.
· Функции, работающие с регистрами, распространяются только на латиницу.
· В С++ некоторые параметры функций обработки символов принадлежат типу int (unsigned), поэтому, если число станет больше 128 (255), функция будет работать некорректно.
· Перед первым обращением к строке она должна быть объявлена и проинициализирована. Во многих случаях в качестве начального значения строки необходимо бывает задать пустую строку. Такую инициализацию можно выполнить с помощью вызова функции
strcpy(s, "");
но более эффективным будет присваивание
*s=0;
Кроме того пустую строку можно инициализировать
char s[10]="";
или
char s[10]="\0";,
но при этом размер строки должен быть задан.
· Функции копирования (кроме strncpy()) не проверяют длину строки. Размер строки-приемника должен быть больше, чем размер источника на 1 символ (для символа '\0' ).
Основные функции работы со строками приведем в таблице 1.
Таблица 1. Основные функции работы со строками
Функции для работы со строками – файл 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 | unsignedstrlen (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 strtod (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 в буквы верхнего регистра |
Приведем примеры использования функций для обработки строк:
1) присваивание выполняется с помощью функций стандартной библиотеки или посимвольно «вручную». Например, чтобы присвоить строке р строку а можно воспользоваться функциями strcpy() или strnсpy(). При вызове функции strncpy() следует помнить, что, если длина копируемой строки превосходит параметр kol, то строка-получатель не будет завершена символом '\0'. В этом случае такой символ надо дописывать в конец строки вручную.
char a[100] = “Строковая константа”;
char *p = new char [m];
strcpy(p,a);// копирование всех символов строки а + «\0» в р
strncpy(p,a,strlen(a)+1); //копирование указанного количества
//(strlen(a)+1)символов строки а в строку р
Для использования этих функций следует подключить заголовочный файл <string.h>.
Функция strlen(a) возвращает фактическую длину строки а не включая нуль-символ.
2) для преобразования строки в целое число используется функция atoi(), в длинное целое – atol(), в вещественное число с двойной точностью – atof().
Пример применения функций преобразования:
char a[]= “10) Рост – 162 см, вес – 59.5 кг”;
int num;
long rost;
double ves;
num = atoi(a);
rost = atol(&a[11]);
ves = atof(&a[25]);
cout << num << ‘ ‘ << rost << ‘ ‘ << ves;
3) Операция вычисления размера (в байтах) sizeof действует для объектов символьного типа и строк.
// Определение размера строк#include "stdafx.h"#include <iostream>using namespace std;int _tmain(int argc, _TCHAR* argv[]) { char s1[10]="string1"; int k=sizeof(s1); cout<<s1<<"\t"<<k<<"\n"; char s2[]="string2"; k=sizeof(s2); cout<<s2<<"\t"<<k<<"\n"; char s3[]={'s','t','r','i','n','g','3','\0'}; /*окончание строки '\0' следует соблюдать, формируя в программах строки из отдельных символов*/ k=sizeof(s3); cout<<s3<<"\t"<<k<<"\n"; char *s4="string4"; //указатель на строку, ее нельзя изменить k=sizeof(s4); cout<<s4<<"\t"<<k<<"\n"; system("pause"); return 0;}Результат выполнения программы:
string1 10 – выделено 10 байтов, в том числе под '\0'
string2 8 – выделено 8 байтов (7 + 1 байт под '\0' )
string3 8 – выделено 8 байтов (7 + 1 байт под '\0' )
4) Сравнение строк с помощью функции strcmp() осуществляется побайтово в лексикографическом порядке, то есть в порядке следования соответствующих байтов строк в таблице кодировки. Именно поэтому значения элементов в строках зависят от регистра.
При использовании библиотечных функций следует иметь в виду, что указатель на строку и имя массива символов указывают на адрес размещения строки в памяти. Это означает, что изменения значений элементов строки сохраняются после завершения работы функции. Чтобы не допустить изменений в строке используется указатель на константу, который не позволит модифицировать данные, хранящиеся по адресуемой области памяти.
Пример 1.
//Программа демонстрирует работу функций из файла stdlib.h #include "stdafx.h"#include <iostream>using namespace std;int _tmain(int argc, _TCHAR* argv[]){ char sv[]="23.547", si[]="1234", sl[]="-112424", st1[15],st2[25],st3[15]; double v; int i; long l,t=457821; v=atof(sv); printf("Преобразование строки в вещественное число = %f\n",v); i=atoi(si); printf("Преобразование строки в целое число = %d\n",i); l=atol(sl); printf("Преобразование строки в длинное целое число = %ld\n",l); printf("Преобразование длинного целого числа в строку = %s\n", ultoa(t,st1,10)); printf("Преобразование длинного целого числа в строку = %s\n", ultoa(t,st2,2)); printf("Преобразование длинного целого числа в строку = %s\n", ultoa(t,st3,16)); system("pause"); return 0;}Пример 2.
//Программа демонстрирует работу функций из файла 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;}Пример 3.
//Поиск множества неповторяющихся символов строки#include "stdafx.h"#include <iostream>using namespace std;int _tmain(int argc, _TCHAR* argv[]){ char st[80]; int i,j,flag,len; printf("Введите строку: "); gets(st); len=strlen(st); //длина строки printf("Неповторяющиеся символы строки образуют множество: "); for (i=0;i<len;i++){ flag=0; //флаг проверки на совпадение for (j=0;j<i;j++) //сравнение символа с предыдущими if (st[i]==st[j]) flag=1; if (flag==0)printf("%c",st[i]); } system("pause"); return 0;}Пример 4.
/*Удаление лишних левых и внутренних пробелов в строке при выводе*/#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;}
Строки и указатели
Строки в языке С++ представляют собой массив символов. Поскольку имя массива без индексов является указателем на первый элемент этого массива, то при использовании функций обработки строк им будут передаваться не сами строки, а указатели на них. Так как все строки в языке С++ заканчиваются нулевым символом, который имеет значение <ложь>, то условие в операторе while(*str) будет истинным до тех пор, пока программа не достигнет конца строки.
При разработке функций для работы со строками в большинстве случаев целесообразно применять указатели. Указатель на строку – адрес начала расположения строки в памяти.
Адрес строки– это указатель на блок непрерывной области памяти, с которого начинает располагаться массив символов.
В силу специфики представления строк в виде символьного массива сами строки, строковые константы, заключенные в кавычки, и указатели на строки обрабатываются эквивалентно.
Строки передаются в функции в качестве параметров как массивы символов или как указатели типа char.
Обращение к конкретному элементу строки можно осуществить посредством адресации индексированного имени строки.
При формировании строки без использования стандартных функций требуется дописывать символ конца строки.
С помощью указателей на константы можно защитить строку от изменений.
Копирование строк с помощью указателей осуществляется через объявление нового указателя, адресующего область памяти, занимаемую строкой или подстрокой.
on_load_lecture();
Приведем примеры фрагментов программ:
/*Пример пользовательской функции копирования строки 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);
вместо «!=0» можно записать «!=NULL» /*
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
Адресация на тот же участок памяти объясняется:
1) неэффективностью повторного хранения уже имеющихся данных,
2) относительной программной трудоемкостью копирования байтов,
3) для хранения адреса строки требуется гораздо меньше места, чем для самой строки.
В данном контексте понятие эффективности носит относительный характер, так как иногда в программе полезным бывает хранение резервной копии введенных данных.
Работа с символами.
Для хранения отдельных символов используются переменные типа char. Их ввод – вывод также может выполняться как с помощью классов ввода-вывода, так и с помощью функций библиотеки.
При использовании классов ввод – вывод осуществляется с помощью операций помещения в поток >> и извлечения потока <<, так и методов get() и get(char):
#include <iostream.h>
int main(){
char c, d, e;
cin >> c; // так ввести пробел нельзя
cin >> d >> e;
cout << c << d << e;
c = cin.get(); //возвращает код символа в с
cin.get(d); cin.get(e); // запись символов d и е в переменные
cout << c << e;
return 0;}
В заголовочном файле <stdio.h> определены функции для стандартного ввода (getchar()) и вывода (putchar()):
getchar()– функция (без параметров) используется для ввода одиночного символа из входного потока. Она возвращает 1 байт информации (символ) в виде значения типа int. Это сделано для распознавания ситуации, когда при чтении будет достигнут конец файла.
putchar(ch)– функция используется для вывода одиночного символа, то есть помещает в стандартный выходной поток символ ch. Аргументом функции вывода может быть одиночный символ (включая знаки, представляемые управляющими последовательностями), переменная или функция, значением которой является одиночный символ.
char c, d;
c = getchar();
d = getchar(); putchar(d);
Например:
/*Программа считывает из входного потока один символ, а затем выводит его на экран*/#include "stdafx.h"#include <iostream>using namespace std;int _tmain(int argc, _TCHAR* argv[]){ char ch; ch=getchar(); putchar(ch); system("pause"); return 0;}Пример следующий. Введите предложение, в конце которого стоит точка, и подсчитайте общее количество символов, отличных от пробела (не считая точки).
#include "stdafx.h"#include <iostream>using namespace std;int _tmain(int argc, _TCHAR* argv[]){ char z; //z - вводимый символ int k; //k - количество значащих символов printf("Напишите предложение с точкой в конце:\n"); for (k=0; (z=getchar())!='.';) /*выражение z=getchar() заключено в скобки, так как операция присваивания имеет более низкий ранг, чем операция сравнения*/ if (z!=' ') k++; printf("\nКоличество символов=%d",k); system("pause"); return 0;}Результат выполнения программы:
Напишите предложение с точкой в конце:1 2 3 4 5 6 7 8 9 0.Количество символов=10Теперь, когда мы познакомились с основными приемами работы со строками и символами, рассмотрим более сложные примеры программ:
1. Поиск подстроки.
Написать программу, которая определяет, встречается ли в заданной строке заданная последовательность символов. Длина строки не превышает 80 символов, текст не содержит переносов слов, а последовательность не содержит пробелов.
Так как переносы отсутствуют, то текст умещается в одной строке. Для ее хранения выделим строковую переменную длиной в 81 символ (дополнительный для нуль-символа).
Последовательность символов, не содержащая пробелов, длиной так же должна быть не более 80 символов, иначе поиск завершится неудачей. Для ее хранения тоже вывделим строковую переменную, длиной 81 символ.
Результатом работы программы является сообщение либо о наличии заданной последовательности, либо об ее отсутствии.
#include <string.h>
int main(){
const int len = 81; // длина строки и последовательности
char word[len], line[len]; // описание строки и
// последовательности
cout<<”Введите строку не более 80 симв”;
cin.getline(line, len);
cout<<”Введите слово для поиска”; cin >> word;
if (strstr(line, word)) // поиск последовательности в строке
cout<<”Присутствует!” << endl;
else
cout<<”Отсутствует!” << endl;
return 0; }
2. Подсчет количества вхождений слова в строку.
Написать программу, определяющую сколько раз встретилось заданное слово в строке. Длина строки не превышает 80 символов. Текст не содержит переносов слов.
Цель данной задачи состоит в том, чтобы после первого удачного поиска не выходить из цикла просмотра, а увеличить счетчик и продолжить просмотр. Результатом работы программы является количество вхождение слова в текст. Его представим в виде целой переменной.
Слово может находиться либо в начале строки, либо после разделителя или знака пунктуации. Определим слово схематически:
слово =
{начало строки | знак пунктуации | разделитель}
символы, составляющие слово
{конец строки | знак пунктуации | разделитель}
Так как слово может встречаться в строке многократно, поэтому для поиска следует организовать цикл просмотра строки, который будет работать, пока в строке происходит обнаружение заданного слова.
При обнаружении совпадения с символами, составляющими слово, требуется определить, является ли оно самостоятельным словом или частью другого слова (например, искомое слово «кот» может содержаться в словах «котенок», «трикотаж», «трескотня» и т.д.). Следовательно, нужно проверить символ, стоящий после слова, и если слово не находится в начале строки, то и символ перед ним. Эти символы проверяются на принадлежность множеству знаков пунктуации и разделителей.
. . .
int main(){
const int len = 81;
char word[len], line[len];
cout<<”Введите строку не более 80 симв”;
cin.getline(line, len);
cout<<”Введите слово для поиска”; cin >> word;
int l_word = strlen(word); // длина слова
int count = 0; // счетчик количества вхождений
char *p = line; // указатель устанавливаем на начало строки
while( p = strstr(p, word)){
char *c = p; // указатель устанавливаем на начало слова
p += l_word; // указатель перемещаем на длину введенного
// слова
// слово не в начале строки?
if (c != line)
// символ перед словом не разделитель?
if(!ispunct(*(c-1)) && !isspace(*(c-1)) continue;
// символ после слова разделитель?
if(ispunct(*p) || isspace(*p) || (*p ==’\0’)) count++;
}
cout << “Кол-во вхождений слова”<< count << endl;
return 0;
}
В рассмотренном примере вводится служебная переменная с для хранения адреса начала вхождения подстроки. Символы, ограничивающие слово, проверяются с помощью функций, хранящихся в заголовочном файле <ctype.h>. Следующий за словом символ проверяется также на признак конца строки (нуль-символ).
Для многократного поиска вхождения подстроки в заголовке цикла используется функция strstr(). Очередной поиск должен выполняться с позиции, следующей за найденной на предыдущем шаге подстрокой. Для хранения этой позиции определяется вспомогательный указатель р, который на каждой итерации цикла наращивается на длину подстроки.
Давайте теперь рассмотрим другой вариант решения этой задачи. В С++ есть функция strtok(), которая разбивает переданную ей строку на лексемы (слова) в соответствии с заданным набором разделителей. Теперь нам не придется выделять и проверять начало и конец слова «вручную», а лишь сравнить с искомым словом слово, выделенное с помощью strtok(). Правда список разделителей придется задать вручную.
. . .
int main(){
const int len = 81;
char word[len], line[len];
cout<<”Введите строку не более 80 симв”;
cin.getline(line, len);
cout<<”Введите слово для поиска”; cin >> word;
char razdel[] = “,.!/”?<>)(|\*;:”; // ввод разделителей
int count = 0; // счетчик количества вхождений
char *token;
token = strtok(line, razdel); // адрес 1-го слова
while( token != NULL){
/* strtok заменяет на NULL разделитель, наход-ся после
найденного слова */
if(!strcmp(token, word)) count++; // сравнение слов
token = strtok(NULL, razdel); // поиск следующего слова
}
cout << “Кол-во вхождений слова”<< count << endl;
return 0;
}
Задание.
Для выданного преподавателем варианта задачи написать и отладить программу на языке С++, которая содержит обработку строк.
Использование специальных библиотечных функций и применение способа обработки строки как символьного массива обоснуйте.
5. Требования к отчету по домашней работе:
Отчет должен содержать:
1) распечатку или текст программы с комментариями;
2) результаты работы программы.
Варианты заданий.
1.Определить, сколько раз в сформированной вами строке встречается сочетание символов «а» и «в».
2. Определить, сколько раз в сформированной вами строке повторяются выбранные символы, из которых состоит алфавит.
3. Определить, сколько раз в сформированной вами строке встречается каждый из символов, и какое из заданных сочетаний этих символов наиболее часто встречаются.
4. Определить, сколько однотипных сочетаний (сочетания задаются интерактивно) содержится в списке фамилий студентов вашей группы.
5. Составить программу определения слов, содержащих цифровые символы.
6. Разработать программу кодирования и декодирования текста. Алфавит содержит 20 символов.
7. В произвольно взятом предложении произвести замену слов, расположенных на чётных и нечётных позициях.
8. В произвольно сформированной строке, содержащей 60 латинских букв, требуется все вхождения lat заменить на tal.
9. В произвольно сформированной строке, удалить первое вхождение АД, если такое есть. Образующуюся дыру заполнить последними символами, а в конец добавить пробелы.
10. В произвольно сформированной строке, заменить на РОВ первое вхождение С, если такое есть.
11. Выделить часть строки (первое вхождение) расположенной между двумя буквами. Буквы задаются в диалоге.
12. В произвольно взятом предложении отпечатать слова, у которых совпадают более двух букв.
13. В произвольно взятом предложении определить слово, содержащее максимальное количество гласных букв.
14. В произвольно взятом предложении напечатать слова в обратном порядке.
15. В произвольно взятом предложении напечатать слова в алфавитном порядке.
16. Определить количество слов в заданном предложении, а также количество букв.
17. В произвольно взятом предложении удалить все лишние пробелы.
18. Вывести на печать первую и последнюю букву каждого слова.
19. В произвольно взятом предложении определить количество слов содержащих цифровые символы.
20. В произвольно взятом предложении определить количество слов заканчивающихся на мягкий знак.
21. В произвольно взятом предложении заменить слово « республика » на « государство ».
22. В произвольно взятом предложении определить слово, состоящее из максимального количества символов.
23. В произвольно взятом предложении выделить слова заключённые в кавычки.
24. В произвольно взятом предложении (английский шрифт) заменить каждую первую букву слов, начинающихся с гласной буквы, на прописную.
25. В произвольно взятом предложении заменить каждую цифру 0…9 на слова «ноль», «один», …, «девять».
26. В произвольно взятом предложении вывести на экран все слова, начинающиеся на гласную букву.
27. В произвольно взятом предложении определить количество слов, состоящих из не более чем четырех символов.
28. В произвольно взятом предложении поменять каждые два слова местами и вывести его на экран.
29. В произвольно взятом предложении вывести на экран слова, содержащие заданное количество букв.
30. В произвольно взятом предложении подсчитать количество знаков препинания.
7. Контрольные вопросы.
1. В чем отличие символьной константы и строкового литерала?
2. Перечислите способы инициализации строки.
3. В чем состоит особенность работы со строками?
4. В чем состоит особенность ввода/вывода строк?
5. Как использовать указатель на строку?
Домашняя работа № 2.