Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Lek11.doc
Скачиваний:
14
Добавлен:
15.11.2018
Размер:
139.78 Кб
Скачать

Лек11: Строки.

В лекциях 11 и 12 описаны два типа данных, значения которых представляют строки символов. Первый из них — массив базового типа char, в котором хранится последовательность символов строки, а конец строки отмечается нулевым симво­лом '\0'. Это старый способ представления строк, унаследованный языком C++ от языка С. Строки данного типа, называемые строками С, все еще широко ис­пользуются, и вам часто придется с ними сталкиваться. Например, строковые константы в кавычках, такие как "Hello", реализуются в C++ как строки С.

Стандарт ANSI/ISO языка C++ включает более современный способ представле­ния строк в виде объектов класса string. Это второй строковый тип, рассматри­ваемый в Лек15.

11.1. Массивы для хранения строк

В этом вопросе описывается способ представления строк символов, унаследован­ный языком C++ от языка С. Хотя строки С несколько «старомодны», они по-прежнему широко используются и являются неотъемлемой частью языка C++.

Строковые значения и строковые переменные С

Одним из способов представления строк является использование массива базо­вого типа char. Например, строку "Hello" удобно представить как массив из шести индексированных переменных: пяти букв слова "Hello" и одного нулевого символа '\0', служащего маркером конца строки. Символ '\0' называется нуль-символом или нулевым символом, а когда он используется в качестве маркера конца стро­ки — нуль-терминатором. При использовании таких маркеров программа может считывать массивы посимвольно и знать, когда следует остановиться. Строка, хранящаяся в описанном формате, называется строкой С.

В программе C++ нуль-символ записывается как ' \0', то есть в виде двух симво­лов, но на самом деле, подобно символу новой строки '\n', он является одним символом. Как и любое другое символьное значение, он может храниться в пере­менной типа char или элементе массива с базовым типом char.

Нуль-символ '\0'

Нуль-символ '\0' отмечает конец строки С, хранящейся в символьном массиве. Такой массив часто называют строковой переменной С. Хотя нуль-символ записывается в ви­де двух символов, это один символ, который может храниться в переменной типа char или элементе массива базового типа char.

Вам уже приходилось пользоваться строками С. Например, литеральная строка, подобная "Hello", хранится в виде строки С, хотя это редко имеет значение для программы.

Строковая переменная С представляет собой просто массив символов. Так, сле­дующее объявление массива:

char s[10];

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

Массив длиной десять символов вмещает строку из девяти символов и нуль-сим­вол '\0', отмечающий ее конец.

Строковая переменная С является частично заполненным массивом символов. Подобно другим частично заполненным массивам, она содержит данные в идущих подряд элементах, начиная с нулевого. И в ней занято столько позиций, сколько нужно для хранения данных. Однако для отслеживания количества заполненных элементов массива ей не требуется отдельная переменная типа int. Информация о месте окончания строки содержится в ней самой — после последнего символа строки в строковой переменной С располагается специальный символ '\0'. По­этому, если в переменной s содержится строка "Hi Mom!", элементы массива запол­нены следующим образом:

s[0] s[l] s[2] s[3] s[4] s[5] s[6] s[7] s[8] s[9]

H

i

M

o

m

!

\0

?

?

Символ '\0' используется в качестве сигнального значения, отмечающего конец строки С. Если считывать символы строки, начиная с элемента s[0], затем s[l], s[2] и т. д., то дойдя до символа ' \0', вы будете знать, что достигли конца строки. Поскольку этот символ всегда занимает один элемент массива, максимальная дли­на строки, которую может вместить массив, на единицу меньше объявленного размера этого массива.

Еще раз подчеркнем: в конце строковой переменной С обязательно должен рас­полагаться нуль-символ ' \0'. Отличие этого типа массива от остальных заключа­ется не в структуре, а состоит в том, что он, представляя собой обычный массив символов, используется особым образом.

Как видно из следующего примера, строковую переменную С можно инициали­зировать при объявлении:

char my_message[20] = "Hi there.";

Обратите внимание на то, что строка С, присваиваемая строковой переменной С, не обязательно заполняет весь массив.

Объявление строковой переменной С

Строковая переменная С — это обычный массив символов, используемый особым об­разом. Она объявляется так же, как любой другой массив символов.

Синтаксис

char имя_массива[максимальный_размер_строки_С + 1];

Пример char my_c_string[11];

Единица прибавляется для того, чтобы массив вмещал нуль-символ ' \0', отмечающий конец хранящейся в массиве строки. В частности, строковая переменная my_c_string в приведенном выше примере вмещает строку С длиной в десять или менее символов.

Инициализируя строковую переменную С, можно опустить размер массива. C++ автоматически присвоит ей размер, который будет на единицу больше, чем длина заключенной в кавычки строки (один дополнительный элемент массива для сим­вола '\0'). Например, объявление

char short_string[] = "abc";

эквивалентно объявлению

char short_string[4] = "abc";

Однако не путайте следующие две инициализации:

char short_string[] = "abc";

и

char short_string[] = {'a', 'b', 'c'};

Они не равнозначны. Первая помещает после символа 'с' символ '\0', а вторая этого не делает (она вообще не помещает в массив символ ' \0' — ни после 'с', ни в каком-либо другом месте).

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

char our_string[5] = "Hi";

Это объявление и инициализация массива символов, включающего следующие элементы: our_string[0], our_string[l], our_string[2], our_string[3] и our_string[4]. Для примера рассмотрим следующий фрагмент программы:

int index = 0;

while (our_string[index] != '\0')

{

our_string[index] = 'X';

index++; }

Данный код изменяет строковое значение, хранящееся в переменной our_string, помещая в нее строку С, состоящую только из символов 'X'.

Инициализация строковой переменной С

Строковую переменную С можно инициализировать при объявлении, как в следую­щем примере:

char rny_string[] = "DoBeDo";

Эта инициализация автоматически помещает в конец строки С символ '\0'.

Если в квадратных скобках не задано число, создается массив, длина которого на еди­ницу больше длины помещаемой в него строки. Так, приведенный оператор объявляет массив my_string из девяти индексированных переменных (восемь для символов стро­ки "Do Be Do" и один для нуль-символа '\0').

При работе с такими индексированными переменными нужно внимательно сле­дить, чтобы символ ' \0' не был заменен каким-нибудь другим значением, посколь­ку при отсутствии этого символа массив перестанет вести себя, как строковая пе­ременная С. Например, код

char happy_string[7] = "DoBeDo";

happy_string[6] = Z’;

изменяет массив happystring так, что в нем больше не содержится строка С.

После выполнения приведенного кода массив happy_string будет по-прежнему со­держать шесть букв строки "DoBeDo", но в нем не будет нуль-символа, отмечающе­го конец строки С (он заменен символом 'Z'). Многие функции для работы со строками требуют обязательного наличия нуль-символа ' \0' и без него работают неправильно. В качестве еще одного примера можно рассмотреть приведенный выше цикл while, изменяющий символы строковой переменной ourstring. Цикл заменяет символы до тех пор, пока не встретит символ ' \0', а в случае его отсут­ствия он может «обработать» большой фрагмент памяти с непредсказуемыми по­следствиями. Цикл while можно переписать следующим образом:

int index = 0;

while ( (our_string[index] != '\0') && (index < SIZE) )

{

our_string[index] = 'X';

index++; }

чтобы он не полагался на наличие символа ' \0' и ни в коем случае не выходил за переделы массива.

В этом примере SIZE — именованная константа, равная объявленному размеру массива our_string.

Оператор

char *str = "Vasia"

создает не строковую переменную, а указатель на строковую константу.

При работе со строками часто используются указатели.

Рассмотрим процесс копирования строки srcв строку dest.

#include <iostream.h>

int main(){

char *src = new char [10];

char *dest = new char [10], *d = dest;

cin << src;

while ( *d++ = *src++);

cout << dest;}

11.2. Ловушка: использование операторов = и == со строками С

Строковые значения и переменные С отличаются от значений и переменных дру­гих типов данных, и многие операции языка C++ к ним неприменимы. Так, нель­зя использовать строковую переменную С в операторе присваивания. Если же по­пытаться сравнить две строки С посредством оператора = =, результат будет не таким, как ожидалось. Это объясняется тем, что строки С являются массивами.

Присваивание значения строковой переменной С выполняется не так просто, как другим переменным C++. Скажем, следующий оператор присваивания:

char a_string[10];

a_string = "Hello";

недопустим.

Хотя в объявлении такой переменой можно пользоваться знаком равенства для ее инициализации, больше нигде в программе это не разрешается. Знак равенства в объявлении переменной

char happy_string[7] = "DoBeDo";

означает именно инициализацию, а не присваивание, которое выполняется иначе.

Существуют разные способы присваивания значения строковой переменной С, простейший из них заключается в вызове стандартной функции strcpy:

strcpy(a_string, "Hello");

Этот вызов присваивает переменной a_string строку "Hello". К сожалению, дан­ная версия функции strcpy не проверяет, превышает ли размер строки размер строковой переменной.

Во многих реализациях C++ имеется более безопасная версия данной функции, называемая strncpy (с буквой n). У нее есть третий аргумент, в котором задается максимальное количество копируемых символов. Например:

char another_string[10];

strncpy(another_string, a_string_variable, 9);

Вызов копирует максимум девять символов из строковой переменной a_string_va­riable (независимо от ее длины) в строковую переменную another_string.

Проверку эквивалентности двух строковых переменных С нельзя выполнять обычным способом (то есть с помощью оператора ==). Данный оператор можно использовать со строками С для других целей. Поэтому если применить его для сравнения двух строк, результат окажется неверным, и при этом даже не будет выведено сообщение об ошибке. Сравнение двух строк С на эквивалентность вы­полняется с помощью стандартной функции strcmp. Вот так:

if (strcmp(c_stringl, c_string2))

cout << "The strings are NOT the same.";

else

cout << "The strings are the same.";

Обратите внимание на то, что функция strcmp работает несколько необычно — она возвращает значение true, когда строки не равны. Эта функция сравнивает две строки посимвольно, и если для очередной пары символов код символа из строки c_string1 оказывается меньше кода символа из строки c_string2, она прекращает проверку и возвращает отрицательное число. В случае же когда код символа из строки cstringl оказывается больше кода символа из строки c_string2, она воз­вращает положительное число. Ну а если строки одинаковы, функция strcmp воз­вращает 0. При сравнении символов двух строк используется лексикографический (словарный) порядок. Когда обе строки содержат символы одного регистра, этот порядок совпадает с алфавитным.

Таким образом, функция strcmp возвращает отрицательное число, положительное число или 0 в зависимости от того, окажется первая из переданных ей строк мень­ше, больше или равной второй с точки зрения их лексикографического порядка. Если использовать возвращаемый ею результат в качестве логического выраже­ния в операторе if или в цикле для проверки равенства двух строк С, ненулевое значение будет преобразовано в true, a 0 — в false. При тестировании программ, выполняющих такую проверку, не забывайте об этой «логике наоборот».

Компиляторы C++, соответствующие стандарту ANSI/ISO, поддерживают более безопасную версию функции strcmp с третьим аргументом, в котором задается максимальное количество сравниваемых символов.

Функции strcpy и strcmp располагаются в библиотеке с заголовочным файлом <cstring>. Для их использования нужно добавить в начало программы следую­щую директиву:

#include <cstring>

Обе эти функции не требуют приведенной ниже (или подобной ей) директивы:

using namespace std;

но она может понадобиться в других частях программы.

Библиотека cstring

Для объявления и инициализации строк С не требуется никакой директивы include или using. Однако при обработке строк вы наверняка будете применять те или иные предопределенные функции из библиотеки cstring. Поэтому, решив воспользоваться строками С, лучше сразу включите в начало файла программы директиву

#include <cstring>

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]