2

I got this simple program read in a string like "13 11 9 10". I wanna split string then sort them. however the sort() seems not working, any help? input: 13 11 9 10 , output: 13 11 9 10 Thanks!

#include <string>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

vector<int> split(string s)
{
    istringstream iss(s);
    vector<int> result;

    do{
        string sub;
        iss>>sub;
        if(sub!="")
            result.push_back((int)atoi(sub.c_str()));
    }while(iss);

    return result;
}
int main(void)
{   
    string s;
    while(cin>>s)
    {
        vector<int> vec;
        vec=split(s);
        sort(vec.begin(), vec.end());
        for (int i = 0; i < vec.size(); ++i)
        {
            cout<<vec[i]<<endl;
        }
    }
}
pythoniku
  • 3,532
  • 6
  • 23
  • 30
  • 1
    http://liveworkspace.org/code/c42d25b1ae979db4044c8cb4b5d3cb51 it works. – ForEveR Jul 18 '12 at 07:01
  • The problem is not with `std::sort()`, but with your `split(string)` method. – iammilind Jul 18 '12 at 07:02
  • The problem is at `cin>>s`, which already splits your input string. Try something like `getline()` instead. – timrau Jul 18 '12 at 07:05
  • @iammilind: Nope, the split method is okay. – Benjamin Lindley Jul 18 '12 at 07:05
  • 1
    @BenjaminLindley Not really. It has at least two errors: it accesses `sub` without checking if the read has succeeded, and it doesn't verify anything. (Of course, since it will never be passed a string with any white space in it, it will never find more than one entry.) – James Kanze Jul 18 '12 at 07:37

2 Answers2

9

That's because cin >> s stops at the first whitespace.

In other words, if you type 1 4 2 3, s contains 1 only, and not the entire line.

Instead, use the following to read the entire line:

std::getline(std::cin, s);
user703016
  • 37,307
  • 8
  • 87
  • 112
  • 2
    In addition, don't use atoi, have a look here http://stackoverflow.com/questions/200090/how-do-you-convert-a-c-string-to-an-int – Johan Lundberg Jul 18 '12 at 07:10
  • 1
    I find it worth mentioning that I don't see `std::stoi` anywhere in the link, or the duplicate of it. That's probably the best method if it's available. – chris Jul 18 '12 at 07:20
  • @chris If it's available; it's part of C++11. And from the specification, it seems to suffer from the same problems as `atoi`: no real error checking is possible. In the end, you've got to go with `strtol`, setting `errno` to 0 before hand, and passing a pointer to a place where `strtol` will store the end pointer, then verifying that `errno == 0 && end != start && *end == '\0'`. – James Kanze Jul 18 '12 at 07:46
  • @JamesKanze, No error checking? It has two possible exceptions to throw in the case of an error: http://en.cppreference.com/w/cpp/string/basic_string/stol. If that's why you added real there, it's still possible to catch them and handle them in the same way as you would a bad result from `strtol`. – chris Jul 18 '12 at 07:48
  • @chris It only throws an error if `strtol` reports an error. That covers the case where `errno != 0` above (I suppose---the standard doesn't say what "reports an error" means with regards to `strtol`.) You still have the problem of something like `"abcxyz"`, where `strtol` simply returns `0`, without reporting an error. – James Kanze Jul 18 '12 at 08:29
  • @JamesKanze, I thought that would be taken care of by `std::invalid_argument`, and it [looks like it is](http://ideone.com/A1oK2). – chris Jul 18 '12 at 11:53
  • @chris According to the standard, "Throws: `invalid_argument` if `strtol`, `strtoul`, `strtoll` or `strtoull` reports that no conversion could be performed.[...]" According to the C standard, given `"abcxyz"`, the function should return `0`, and _not_ report an error. (This surprised me too, but I was recently bitten by it You need extra concerning how much data was used to generate the return value.) – James Kanze Jul 18 '12 at 12:55
  • @JamesKanze, Well, I see your point then. Is that a bug with (a possibly older version of) GCC? I don't have `stoi` on my 4.7.1 so I can't check there. – chris Jul 18 '12 at 13:00
  • @chris `std::stoi` is a C++11 function, so it's likely that most people don't have it. – James Kanze Jul 18 '12 at 17:15
  • Sorry, Cicada; that got a bit longer than I was expecting. @JamesKanze, Yes, 'twould be nice, but that's the reality. I don't even have it *with* C++11 yet. Thanks for the standard reference to that, though. – chris Jul 18 '12 at 17:19
0

your main section of code is incorrect, cin already splits data into parts, use cin.getline with buffer or what Cicida suggests above, my working code looks like this:

string s;
char buffer[ 256 ];
do
{
    cin.getline( buffer, 255 );
    s.assign( buffer );
    vector<int> vec;
    vec=split(s);
    sort(vec.begin(), vec.end());
    for (int i = 0; i < vec.size(); ++i)
    {
        cout<<vec[i]<<endl;
    }
}while( !s.empty( ));