2
\$\begingroup\$

Sometimes, I need to read two integer parameters in a single input line, separated by a whitespace.

I have these two functions that seem to do the job just fine:

#include <iostream>
#include <sstream>
#include <deque>

// Splits a string by its whitespaces and returns a deque with each item.
deque<string> split(string original) {
    deque<string> result;
    string buffer;
    stringstream stream(original);
    while (stream >> buffer) {
        result.push_back(buffer);
    }
    return result;
}

// Reads two integer parameters from a single line, separated by a whitespace
void getTwiceInput(int &a,int &b) {
    string input;
    getline(cin,input);
    deque<string> deck = split(input);
    stringstream ss;
    ss << deck[0];
    ss >> a;
    ss.clear();
    ss << deck[1];
    ss >> b;
}

So in my program I do this call:

int x,y;
getTwiceInput(x, y);

Is there an easier way to achieve this? It is a bit tiring having to type all of that just to achieve this for every programming challenge given.

\$\endgroup\$
3
  • \$\begingroup\$ If you're always reading two values from a line, consider using std::pair instead of std::deque. In fact, why do you even use std::deque? Use just std::vector, it's generally more efficient except cases where you have to insert values in random position, especially in front. \$\endgroup\$
    – Archie
    Commented Apr 18, 2013 at 9:03
  • \$\begingroup\$ @Archie: Haha, yeah XD. I'm too used to deque. \$\endgroup\$
    – Saturn
    Commented Apr 18, 2013 at 9:37
  • 2
    \$\begingroup\$ Why not: std::cin >> x >> y; \$\endgroup\$ Commented Apr 19, 2013 at 17:16

3 Answers 3

3
\$\begingroup\$

I would recommend to use std::stringstream for split. Here is how I think this function would look like:

#include <sstream>
#include <vector>
#include <iterator>

template<typename T>
std::vector<T> split(const std::string& line) {
    std::istringstream is(line);
    return std::vector<T>(std::istream_iterator<T>(is), std::istream_iterator<T>());
}

And here is how to use it:

std::string line = "1.2 3.4 5.6e7";
std::vector<double> vec = split<double>(line);

This method is more general and can split more than two elements as well as parse them to any type provided as template parameter, as long as it is “readable” by operator>>.

\$\endgroup\$
1
  • \$\begingroup\$ Would std::assign be better than std::copy ? \$\endgroup\$ Commented Apr 18, 2013 at 19:17
3
\$\begingroup\$

I can think of two more ways of doing it.

1. Using iostream iterators. (Following code is from here)

#include <iostream>
#include <iterator>
using namespace std;

int main () {
  double value1, value2;
  cout << "Please, insert two values: ";

  istream_iterator<double> eos;         // end-of-stream iterator
  istream_iterator<double> iit (cin);   // stdin iterator

  if (iit!=eos) value1=*iit;

  iit++;
  if (iit!=eos) value2=*iit;

  cout << value1 << "*" << value2 << "=" << (value1*value2) << endl;

  return 0;
}

2. Converting string to int using atoi() rest everything will be same.

\$\endgroup\$
1
  • \$\begingroup\$ Streams are nice, but using atoi() is not a good idea. Better use std::stoi() if your compiler handles C++11 Standard. \$\endgroup\$
    – Archie
    Commented Apr 18, 2013 at 9:05
3
\$\begingroup\$

Sorry, what is the problem with:

 cin >> x >> y; 

Or:

void getTwiceInput(int &a,int &b) {
    string input;
    getline(cin,input);
    stringstream ss(input);
    ss >> a >> b;
}

?? Here maybe you need to detect format errors (no mummers or only one per line, or more than two..) But your code dont do that anyway.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.