Что именно делает stringstream?

59

Я пытаюсь изучить С++ со вчерашнего дня, и я использую этот документ: http://www.cplusplus.com/files/tutorial.pdf (стр. 32). Я нашел код в документе, и я его запустил. Я попытался ввести Rs 5.5 для цены и целое число для количества, а выход был равен 0. Я попытался ввести 5.5 и 6, и результат был верным.

// stringstreams
#include <iostream> 
#include <string> 
#include <sstream> 

using namespace std; 

int main () 
{ 
  string mystr; 
  float price = 0; 
  int quantity = 0; 

  cout << "Enter price: "; 
  getline (cin,mystr); 
  stringstream(mystr) >> price; 
  cout << "Enter quantity: "; 
  getline (cin,mystr); 
  stringstream(mystr) >> quantity; 
  cout << "Total price: " << price*quantity << endl; 
  return 0; 
}

Вопрос: Что именно делает команда mystring? Цитирование из документа:

"В этом примере мы получаем числовые значения со стандартного ввода косвенно. Вместо извлечения числовых значений непосредственно из стандартный ввод, мы получаем линии от стандартного ввода (cin) в string object (mystr), а затем мы извлекаем целочисленные значения из эту строку в переменную типа int (количество)."

Мое впечатление заключалось в том, что функция примет неотъемлемую часть строки и использует ее как входную.

(я точно не знаю, как задать вопрос здесь. Я также новичок в программировании) Спасибо.

  • 18
    Этот пример довольно странный, я никогда не видел, чтобы stringstream использовал его таким образом. Я обычно загружаю строку, преобразую ее и затем извлекаю по частям, однако это, очевидно, имеет небольшое преимущество, поскольку cin уже является входным потоком ... Итак, cin >> price >> quantity; было бы намного проще. Это было бы хорошей причиной НЕ использовать учебники cplusplus.com.
  • 6
    Забавно, что этот урок был моим первым знакомством с C ++. Оглядываясь назад, он довольно беден и неполон. Вместо этого я бы предложил хорошую книгу .
Показать ещё 8 комментариев
Теги:

4 ответа

95
Лучший ответ

Иногда очень удобно использовать stringstream для преобразования строк и других числовых типов. Использование stringstream аналогично использованию iostream, поэтому нелегко учиться.

Stringstreams могут использоваться как для чтения строк, так и для записи данных в строки. Он в основном работает со строковым буфером, но без реального канала ввода/вывода.

Основными функциями-членами класса stringstream являются

  • str(), который возвращает содержимое своего буфера в строковом типе.

  • str(string), которые устанавливают содержимое буфера в строковый аргумент.

Вот пример использования строковых потоков.

ostringstream os;
os << "dec: " << 15 << " hex: " << std::hex << 15 << endl;
cout << os.str() << endl;

Результат: dec: 15 hex: f.

istringstream имеет более или менее одинаковое использование.

Подводя итог, stringstream - это удобный способ манипулировать строками, такими как независимое устройство ввода/вывода.

FYI, отношения наследования между классами:

Изображение 110483

12

Чтобы ответить на вопрос. stringstream в основном позволяет рассматривать объект string как a stream и использовать на нем все stream функции и операторы.

Я видел, что он использовался в основном для форматированного вывода/ввода.

Одним хорошим примером может быть реализация c++ преобразования числа в объект потока.

Возможный пример:

template <class T>
string num2str(const T& num, unsigned int prec = 12) {
    string ret;
    stringstream ss;
    ios_base::fmtflags ff = ss.flags();
    ff |= ios_base::floatfield;
    ff |= ios_base::fixed;
    ss.flags(ff);
    ss.precision(prec);
    ss << num;
    ret = ss.str();
    return ret;
};

Может быть, это немного сложно, но это довольно сложно. Вы создаете объект stringstream ss, изменяете его флаги, помещаете в него номер с помощью operator<< и извлекаете его через str(). Я предполагаю, что можно использовать operator>>.

Также в этом примере буфер string скрыт и не используется явно. Но было бы слишком долго писать о всех возможных аспектах и ​​прецедентах.

Примечание: я, вероятно, украл его у кого-то на SO и уточнил, но у меня нет оригинального автора.

  • 3
    Примечание: использование ret не нужно, можно написать return ss.str(); ,
  • 0
    @MatthieuM. Я думаю, что я не был уверен, что RVO включится, если он будет написан таким образом, или объект, возвращенный ss.str (), выживет в точке выхода. Таким образом, я знаю, что делаю копию, и RVO будет работать. Но вы, скорее всего, правы.
Показать ещё 2 комментария
5

Из С++ Primer:

Тип istringstream читает строку, ostringstream записывает строку, а stringstream читает и записывает строку.

Я сталкиваюсь с некоторыми случаями, когда удобно и лаконично использовать stringstream.

случай 1

От одно из решений для эта проблема с идентификатором. Он демонстрирует очень подходящий случай, когда использование stringstream является эффективным и кратким.

Предположим, что a и b - это комплексные числа, выраженные в строчном формате, мы хотим получить результат умножения a и b также в строчном формате. Код выглядит следующим образом:

string a = "1+2i", b = "1+3i";
istringstream sa(a), sb(b);
ostringstream out;

int ra, ia, rb, ib;
char buff;
// only read integer values to get the real and imaginary part of 
// of the original complex number
sa >> ra >> buff >> ia >> buff;
sb >> rb >> buff >> ib >> buff;

out << ra*rb-ia*ib << '+' << ra*ib+ia*rb << 'i';

// final result in string format
string result = out.str() 

случай 2

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

string simplifyPath(string path) {
    string res, tmp;
    vector<string> stk;
    stringstream ss(path);
    while(getline(ss,tmp,'/')) {
        if (tmp == "" or tmp == ".") continue;
        if (tmp == ".." and !stk.empty()) stk.pop_back();
        else if (tmp != "..") stk.push_back(tmp);
    }
    for(auto str : stk) res += "/"+str;
    return res.empty() ? "/" : res; 
 }

Без использования строкового потока было бы трудно написать такой сжатый код.

1

Вы ввели буквенно-числовые и int, пустые разделители в mystr.

Затем вы попытались преобразовать первый токен (пустой разделитель) в int.

Первым токеном был RS, который не смог преобразовать в int, оставив нуль для myprice, и все мы знаем, что в нулевое время ничего не дает.

Когда вы только вводили значения int во второй раз, все работало так, как вы ожидали.

Это был ложный RS, который вызвал ваш код.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню