декса. Например, чтобы изменить значение 2-го пиксела слева в 4-й строке надо запи-
сать оператор:
bitmap[3][1] = true;
Все сказанное во 2-м параграфе относительно одномерных массивов как пара-
метров функций верно и для двумерных массивов, но у них есть еще одна особен-
ность. В прототипах и заголовках функций можно опускать первую размерность мно-
гомерного массива-параметра (т.е. записывать пустые квадратные скобки "[]"), но все
остальные размерности надо обязательно указывать. Далее в качестве примера приве-
дена функция, заполняющая битовую карту черными пикселами.
void clear_bitmap( bool bitmap[][BITMAP_WIDTH],
int bitmap_height )
{
for ( int row = 0; row < bitmap_height; row++ )
70
for ( int column = 0; column < BITMAP_WIDTH; column++ )
bitmap[row][column] = false;
}
5. Символьные строки
Во многих уже рассматривавшихся программах для вывода на экран часто ис-
пользовались символьные строки, например, ""Введите возраст:"". В Си++ строки
хранятся и обрабатываются в виде символьных массивов, на которые накладывается
дополнительное ограничение (см. п.5.1).
5.1 Завершающий нуль-символ '\0'
Символьный массив для хранения строки должен иметь длину на 1 символ
больше, чем длина строки. В последнем элементе массива хранится специальный
нуль-символ (символ с кодом 0, часто обозначается '\0'). Этот служебный символ
обозначает конец строки, и это общепринятое правило представления строк, которое
соблюдают все библиотечные функции для работы со строками.
На рис. 6 показаны два массива, в которых хранятся символы строки ""Введите
возраст:"", но из них только массив "phrase" является правильным представлением
строки. Хотя и "phrase", и "list" являются символьными массивами, но только
"phrase" имеет достаточную длину для хранения символьной строки ""Введите воз-
раст:"" вместе с завершающим символом "'\0'".
Рис. 6.. Правильное ("phrase") и неправильное ("list") представление сим-
вольной строки.
5.2 Объявление и инициализация символьных строк
Символьные строки описываются как обычные массивы:
char phrase[17];
Массивы можно полностью или частично проинициализировать непосредст-
венно в операторе описания. Список значений элементов массива заключается в фи-
гурные скобки "{}" (это правило верно для любых массивов, а не только для сим-
вольных). Например, оператор
char phrase[17] = { 'В','в','е','д','и','т','е',' ',
'в','о','з','р','а','с','т',
':', '\0' };
71
одновременно и объявляет массив "phrase", и присваивает его элементам значения
согласно рис. 6. То же самое делает оператор:
char phrase[17] = "Введите возраст:";
Если не указывать размер "17", то размер массива будет выбран в соответствии
с количеством инициализирующих значений (с учетом завершающего нуль-символа).
Т.е. строку можно описать с помощью любого из двух следующих операторов:
char phrase[] = { 'В','в','е','д','и','т','е',' ',
'в','о','з','р','а','с','т',
':', '\0' };
char phrase[] = "Введите возраст:";
Очень важно запомнить, что символьные строки хранятся в виде массивов. По-
этому их нельзя приравнивать и сравнивать с помощью операций "=" и "==". Напри-
мер, нельзя записать оператор присваивания:
phrase = "Вы напечатали строку:";
Для копирования и сравнения строк следует применять специальные библио-
течные функции.
5.3 Библиотечные функции для работы с символьными строками
В стандартном библиотечном файле "string.h" хранятся прототипы большо-
го количества полезных функций для обработки символьных строк. Будем полагать,
что в рассматриваемые далее программы этот заголовочный файл включается с по-
мощью директивы препроцессора:
#include <string.h>
Если в программе есть строковая переменная "a_string", то скопировать в нее
содержимое другой строки можно с помощью функции "strcpy(...)":
strcpy( a_string, "Вы напечатали строку:" );
Этот оператор скопирует в массив a_string символы константной строки ""Вы
напечатали строку:"" и добавит в конец массива (т.е. присвоит 21-му элементу) за-
вершающий нуль-символ "'\0'". Вызов оператора
strcpy( a_string, another_string );
приведет к копированию строки, хранящейся в массиве "another_string", в массив
"a_string". При копировании строк важно, чтобы длина массива-приемника
("a_string") была, как минимум, (L+1), где L –длина копируемой строки
("another_string"). В противном случае вызов функции приведет к ошибке выхода за
пределы массива, которая не обнаруживается компилятором, но может привести к
серьезным сбоям во время выполнения программы.
Для вычисления длины строки предназначена функция "strlen(...)". Вызов
"strlen(another_string)" возвращает длину строки "another_string" (без учета нуль-
символа).
Функция "strcmp(...)" выполняет сравнение двух переданных ей строк. Если
строки одинаковы, то эта функция возвратит 0 (т.е. "false"), а если строки различа-
ются, то функция возвратит ненулевое значение.
Функция конкатенации (соединения) строк "strcat(...)" получает два пара-
метра-строки и копирует вторую строку в конец первой. При работе с "strcat(...)",
как и с функцией "strcpy(...)", надо обязательно следить за размером массива-
приемника. Си++ не проверяет, достаточен ли размер первого массива, переданного
72
этой функции, для хранения соединенных строк. При малом размере массива про-
изойдет необнаруживаемая на этапе компиляции ошибка выхода за границы массива.
Работа с библиотечными строковыми функциями продемонстрирована в про-
грамме 5.1.
5.4 Чтение символьных строк из потока ввода с помощью функции "getline(...)"
Для ввода строк (например, с клавиатуры) пригоден оператор ">>", но его при-
менение ограничено, поскольку этот оператор считает пробелы разделителями. До-
пустим, в программе содержатся операторы:
...
...
cout << "Введите имя: ";
cin >> a_string;
...
...
После сеанса работы со следующими экранными сообщениями:
...
...
Введите имя: Вася Иванов
...
...
Переменной "a_string" будет присвоено значение ""Вася"", т.к. оператор ">>"
считает пробел разделителем, который сигнализирует о завершении ввода значения.
Для ввода символьных строк часто более удобной оказывается функция
"getline(...)", имеющая 2 параметра. Например, оператор:
cin.getline(a_string, 80);
позволяет получить от пользователя строку с пробелами длиной до 79 символов (по-
следний, 80-й символ строки –служебный нуль-символ).
В программе 5.1 демонстрируется действие функций "getline(...)",
"strcmp(...)", "strcpy(...)" и "strcat(...)".
#include <iostream.h>
#include <string.h>
const int MAXIMUM_LENGTH = 80;
int main()
{
char first_string[MAXIMUM_LENGTH];
char second_string[MAXIMUM_LENGTH];
cout << "Введите первую строку: ";
cin.getline(first_string,MAXIMUM_LENGTH);
cout << "Введите вторую строку: ";
cin.getline(second_string,MAXIMUM_LENGTH);
cout << "До копирования строки были ";
if ( strcmp(first_string,second_string) )
cout << "не ";
cout << "одинаковыми.\n";
73
strcpy( first_string, second_string );
cout << "После копирования строки стали ";
if ( strcmp(first_string,second_string) )
cout << "не ";
cout << "одинаковыми.\n";
strcat( first_string, second_string);
cout << "После конкатенации первая строка равна: ";
cout << first_string;
return 0;
}
Программа 5.1.
Программа 5.1 в типичном сеансе работы выводит сообщения: