Язык программирования C++. Вводный курс

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


Библиотека 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.      Сформулируйте достоинства и недостатки обоих подходов.


Содержание раздела