Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Липпман.doc
Скачиваний:
9
Добавлен:
14.08.2019
Размер:
7.54 Mб
Скачать

20.8. Строковые потоки

Библиотека iostream поддерживает операции над строковыми объектами в памяти. Класс ostringstream вставляет символы в строку, istringstream читает символы из строкового объекта, а stringstream может использоваться как для чтения, так и для записи. Чтобы работать со строковым потоком, в программу необходимо включить заголовочный файл

#include <sstream>

Например, следующая функция читает весь файл alice_emma в объект buf класса ostringstream. Размер buf увеличивается по мере необходимости, чтобы вместить все символы:

#include <string>

#include <fstream>

#include <sstream>

string read_file_into_string()

{

ifstream ifile( "alice_emma" );

ostringstream buf;

char ch;

while ( buf && ifile.get( ch ))

buf.put( ch );

return buf.str();


}

Функция-член str() возвращает строку – объект класса string, ассоциированный со строковым потоком ostringstream. Этой строкой можно манипулировать так же, как и “обычным” объектом класса string. Например, в следующей программе text почленно инициализируется строкой, ассоциированной с buf:

int main()

{

string text = read_file_into_string();

// запомнить позиции каждого символа новой строки

vector< string::size_type > lines_of_text;

string::size_type pos = 0;

while ( pos != string::npos )

{

pos = text.find( '\n' pos );

lines_of_text.push_back( pos );

}

// ...


}

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

#include <iostream>

#include <sstream>

int main()

{

int ival = 1024; int *pival = &ival;

double dval = 3.14159; double *pdval = &dval;

ostringstream format_message;

// преобразование значений в строковое представление

format_message << "ival: " << ival

<< " адрес ival: " << pival << 'n'

<< "dval: " << dval

<< " адрес dval: " << pdval << endl;

string msg = format_message.str();

cout << " размер строки сообщения: " << msg.size()

<< " сообщение: " << msg << endl;


}

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

string

format( string msg, int expected, int received )

{

ostringstream message;

message << msg << " ожидалось: " << expected

<< " принято: " << received << "\n";

return message.str();

}

string format( string msg, vector<int> *values );


// ... и так далее

Приложение может сохранить такие строки для последующего отображения и даже рассортировать их по серьезности. Обобщить эту идею помогают классы Notify (извещение), Log (протокол) и Error (ошибка).

Поток istringstream читает из объекта класса string, с помощью которого был сконструирован. В частности, он применяется для преобразования строкового представления числа в его арифметическое значение:

#include <iostream>

#include <sstream>

#include <string>

int main()

{

int ival = 1024; int *pival = &ival;

double dval = 3.14159; double *pdval = &dval;

// создает строку, в которой значения разделены пробелами

ostringstream format_string;

format_string << ival << " " << pival << " "

<< dval << " " << pdval << endl;

// извлекает сохраненные значения в коде ASCII

// и помещает их в четыре разных объекта

istringstream input_istring( format_string.str() );

input_istring >> ival >> pival

>> dval >> pdval;


}

Упражнение 20.16

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

int ival = 1024;

double dval = 3.14159;

char cval = 'a';

char *sval = "the end";

printf( "ival: %d\tdval% %g\tcval: %c\tsval: %s",


ival, dval, cval, sval );

печатает:

ival: 1024 dval: 3.14159 cval: a sval: the end

Первым аргументом printf() является форматная строка. Каждый символ % показывает, что вместо него должно быть подставлено значение аргумента, а следующий за ним символ определяет тип этого аргумента. Вот некоторые из поддерживаемых типов (полное описание см. в [KERNIGHAN88]):

%d целое число

%g число с плавающей точкой

%c char


%s C-строка

Дополнительные аргументы printf() на позиционной основе сопоставляются со спецификаторами формата, начинающимися со знака %. Все остальные символы в форматной строке рассматриваются как литералы и выводятся буквально.

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

  1. Получите так же отформатированный результат с помощью объекта класса ostringstream.

  2. Сформулируйте достоинства и недостатки обоих подходов.