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.

asked Apr 18, 2013 at 7:13
\$\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\$ Commented Apr 18, 2013 at 9:03
  • \$\begingroup\$ @Archie: Haha, yeah XD. I'm too used to deque. \$\endgroup\$ 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>>.

answered Apr 18, 2013 at 9:17
\$\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.

answered Apr 18, 2013 at 8:09
\$\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\$ 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.

answered Apr 18, 2013 at 10:40
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.