Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Учебное пособие2013_09_28.doc
Скачиваний:
24
Добавлен:
20.05.2015
Размер:
2.72 Mб
Скачать

11. Символьные переменные и строки. Обработка строк.

Строка представляет собой массив символов, завершающийся так называемым нуль-символом — символом с кодом 0 (’\0’). По положению нуль-символа определяется реальная длина строки. Например, определение переменной-строки из 79 символов выглядит так:

char s1[80];

Строки можно при их определении инициализировать строковыми константами (см. раздел “ Основные типы данных, операции и выражения ”); при этом нуль-символ в конце строки формируется автоматически:

char s1[80] = “Здесь был Вася” ;

либо даже так:

char s1[] = “Здесь был Вася” ;

В последнем случае компилятор сам выделит память, достаточную для размещения строки с завершающим нулём. Если инициализирующая строка короче, чем указанный размер строки, то оставшиеся элементы строки инициализируются символом ‘\0’.

Определить в программе константу-строку MSG можно одним из следующих способов:

#define MSG “Умом Россию не понять”

или

const char MSG[ ] = “Умом Россию не понять”;

Имя переменной-строки (без квадратных скобок) отождествляется в программе с ее адресом. Поэтому операции присваивания и сравнения для строк c завершающим нуль-символом в С/С++ недопустимы. Нельзя, например, использовать такую последовательность предписаний:

char str[80];

str = “ Здесь был Вася ” ;

Для присваивания переменной строкового литерала можно использовать подходящую стандартную функцию библиотеки языка:

strcpy(str, “ Здесь был Вася ”);

Библиотека стандартных функций имеет в своем составе множество полезных функций для работы со строками, в том числе: для вычисления реальной длины строки (strlen()); сцепления строк ( strcat(), strncat()); сравнения строк (strcmp(), strncmp()); поиска вхождения символа в строку (strchr()); поиска подстроки в строке (strstr()) и др. Эти функции описаны в заголовочном файле <string.h> (<cstring>). Более подробно синтаксис каждой из них легко выяснить с помощью справочной системы Интегрированной среды разработки.

Дадим краткое описание важнейших функций

Функция strlen(s1)возвращает длину строки, указанной аргументом s1.

Функция strcpy(s1, s2)копирует содержимое строки s2 в строку s1. Строка s1 должна быть достаточно протяженной, чтобы в неё можно было поместить строку s2. В противном случае возможно аварийное завершение программы.

Функция strcat(s1, s2)присоединяет строку s2 в конец строки s1, при этом строка s2 не изменяется. Обе строки должны завершаться нулевым символом. Результирующая строка s1 также будет завершаться нулевым символом. Строка s1 должна быть достаточно большой, чтобы в нее поместилось, кроме ее исходного содержимого, содержимое строки s2.

Функция strcmp(s1, s2)сравнивает строку s2 со строкой s1 и возвращает значение 0, если они равны. Если строка s1 лексикографически (т.е. в соответствии с алфавитным порядком) больше строки s2, возвращается положительное число; если строка s1 лексикографически меньше строки s2, возвращается отрицательное число. Точнее говоря, функция возвращает разность кодов первой пары несовпавших символов.

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

atof() – преобразует заданную строку в double; atoi() – преобразует строку в int; atol() – в long. Если строку нельзя преобразовать в число, возвращается 0. Обратные преобразования можно осуществить с помощью библиотечной функции sprintf().

В языке C++ существует и другой тип представления строк . Он заключается в применении объектов класса string, который является частью библиотеки классов C++.

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

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

// Программа отлажена вVisual Studio 2008

#include <iostream>

#include <string.h>

#include <string>

using namespace std;

int main()

{ char c1[80], c2[80],c3[80]; //строки с 0-символом

string s1, s2, s3; //объекты класса string

//Присваивание строк

strcpy_s(c1,"Стиль языка С");

strcpy_s(c2, c1);

s1="Стиль языка С++";

s2=s1;

//Сцепление строк

strcpy_s(c3,"1 - ");

strcat_s(c3, c2); cout<<c3<<endl;

s1="2 - ";

s3=s1 + s2; cout<<s3<<endl;

return 0;

}

Результат выполнения программы:

1 – Стиль языка С

2 – Стиль языка С++

Ввод – вывод строк.

Для ввода‑вывода строк естественно пытаться использовать известные нам объекты cin и cout языка C++, а также функции языка С (scanf(), printf(), gets(), puts() и др.)

В отличие от массивов, строки вводятся и выдаются на экран не поэлементно, а целиком, что присуще простым переменным:

char s1[80]; cout << “Как тебя зовут?”;

cin >> S1; cout << “Привет” << S1;

Следует иметь в виду, что если количество вводимых символов превышает длину строки, определённую при её описании, то поведение программы непредсказуемо.

Рассмотрим примеры.

Задача 106. Программа запрашивает имя пользователя и после ответа приветствует его по имени. Используется стиль C++.

#include <iostream.h>

#include <conio.h>

void main()

{

char S1[80];

cout<<"Как тебя зовут? ";

cin>>S1;

cout<<"Привет, "<<S1<<”!”;

getch();

}

Задача 107. Программа запрашивает имя пользователя и после ответа приветствует его по имени. Используется стиль C.

#include <conio.h>

#include <stdio.h>

void main()

{

char S1[80];

printf("Как тебя зовут? ");

scanf("%s", S1);

printf("Привет, %s\n! ", S1);

getch();

}

Протестируйте две приведенные выше программы. Сначала введите имя, состоящее из одного слова. Обе программы корректно обрабатывают введённую строку и выдают правильные результаты. Введите теперь имя, состоящее из двух слов (например, Наполеон Бонапарт). Во втором случае в приветствии выводится только первое слово! Это вызвано тем, что ввод строки средствами cin и scanf() осуществляется до первого пробельного символа (т.е. пробела, знака табуляции и символа перевода строки ‘\n’).

Рассмотрим ещё один пример.

Задача 108.Программа запрашивает имя пользователя и его любимый напиток, а после ответа приветствует его по имени. Используется стильC++.

// Программа отлажена вVisual Studio 2008

#include <iostream>

#include <string.h>

#include <conio.h>

using namespace std;

int main()

{

char name[25],drink[25];

// Устанавливаем локализацию для выходного потока

wcout.imbue( locale( "rus_rus.866" ) );

// Выводим строку на русском !

wcout<<L"Как Вас зовут? ";

cin>>name;

wcout <<L"Ваш любимый напиток? "; cin>>drink;

wcout<<L"Привет, "<<name<<'\n';

wcout<<L"Да, "<<drink<<L" - чудесный напиток"<<endl;

_getch(); return 0;

}

Чтобы помочь вам разобраться в том, что делает эта программа, приведём результаты её работы (полужирным курсивом выделен текст, вводимый пользователем):

Как Вас зовут? Бонапарт Наполеон

Ваш любимый напиток? Привет, Бонапарт

Да, Наполеон - чудесный напиток

Таким образом, текст, введённый после пробельного символа, не игнорируется! Он сохраняется в специальном буфере ввода‑вывода и извлекается оттуда при вызове очередной функции ввода данных. Этим и объясняется, что вводить по оператору

сin >> drink;

ничего не понадобилось: фраза “Наполеон” была извлечена из буфера.

Применение функции scanf() вместо cin приводит к аналогичным результатам. Протестируйте следующую задачу самостоятельно.

Задача 109. Программа запрашивает имя пользователя и его любимый напиток, а после ответа приветствует его по имени. Используется стиль C.

#include <stdio.h>

#include <conio.h>

void main()

{

char name[15],drink[12];

printf("Как Вас зовут? "); scanf("%s",name);

printf("Ваш любимый напиток? "); scanf("%s",drink);

printf("Привет, %s\n",name);

printf("Да, %s - чудесный напиток\n",drink);

getch();

}

В дальнейшем для ввода строк будем в основном использовать функцию gets(S1) (S1 — имя вводимой строки), которая лишена указанного выше недостатка. Эта функция вводит все символы входного потока, в том числе и пробелы, пока не будет нажата клавиша Enter. Код клавиши Enter преобразуется в нуль-символ и все введенные символы заполняют строковую переменную S1. Но и эта функция не безгрешна: если количество вводимых символов превышает длину строки S1, определённую при её описании, то, скорее всего, программа завершится аварийно.

Что же касается вывода строк, то можно с одинаковым успехом применять метод cout, функции printf(), puts():

cout << “Привет, ” << name << endl;

printf (“Привет, %s\n”, name );

puts(“Привет,”); puts(name);

Следует иметь в виду, что функция printf() менее удобна, чем puts(), но более гибкая. В частности, printf(), в отличие от puts(), не выводит автоматически каждую строку текста с новой строки экрана. С другой строки, функция puts() выводит за одно обращение к ней только одну строку символов, а printf() может легко объединить несколько выводимых строк в одну:

сhar name[20], S1[] = “Привет,”;

printf( Как тебя зовут?); gets(name);

printf(“%s %s\n” , S1, name);

Задача 110.Программа запрашивает имя пользователя и его любимый напиток, а после ответа приветствует его по имени. Используются функцииgets(),puts() и printf() для ввода-вывода. Теперь программа работает корректно.

#include "stdafx.h"

#include <stdio.h>

#include <conio.h>

int main()

{

char name[15],drink[12];

puts("Как Вас зовут? "); gets(name);

puts("Ваш любимый напиток? "); gets(drink);

printf("Привет, %s\n",name);

printf("Да, %s - чудесный напиток\n",drink);

_getch(); return 0;

}