3

I'm trying to read multiple integers from a single input line into an array eg. Input: 100 200 300 400, so the array is: a[0] = 100, a[1] = 200, a[2] = 300, a[3] = 400 The thing is, the number of integers are unknown, so the size of the array is unknown.

ylhtravis
  • 105
  • 1
  • 2
  • 10

3 Answers3

8

You should use a container that automatically resizes itself, such as std::vector.

For example, something like this:

#include <string>
#include <iostream>
#include <sstream>
#include <utility>
#include <iterator>

std::string line;
getline(instream, line);
std::istringstream this_line(line);
std::istream_iterator<int> begin(this_line), end;
std::vector<int> values(begin, end);
Benjamin Lindley
  • 101,917
  • 9
  • 204
  • 274
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • I guess you meant to use `std::istream_iterator` and you wanted to use appropriate parenthesis to avoid the most vexing parse. – Dietmar Kühl Feb 19 '12 at 23:14
  • @DietmarKühl: Thanks you pointing out the wrong name. Is that a valid way to avoid most vexing parse? – Ben Voigt Feb 19 '12 at 23:18
  • Yes, it definitely avoids the most vexing parse but unnecessarily requires the use of C++2011. A somewhat more subtle version is `std::vector values(std::istream_iterator(this_line), (std::istream_iterator()))` (note the extra set of parenthesis around the second argument). Also, I had intentionally used `std::istream_iterator` instead of `istream_iterator` ;) – Dietmar Kühl Feb 19 '12 at 23:22
  • @DietmarKühl: Oh fine, no C++11 fun used. C++11 would also allow using `{}` instead of `()`, to avoid parsing as a function declaration, right? – Ben Voigt Feb 19 '12 at 23:23
  • @BenVoigt: yes, I think this is correct although I'm not entirely sure: the "uniform initialization syntax" is **far** from uniform and `std::vector` supports initializer lists: I haven't quite wrapped my head around the interaction between those and the uniform initializations. Since `std::vector` uses `std::initializer_list` this should be OK (need to try it out though). – Dietmar Kühl Feb 19 '12 at 23:30
  • @DietmarKühl: A difference between `values{ begin, end }` and `values{{ first, second }}` perhaps? – Ben Voigt Feb 19 '12 at 23:34
  • @BenVoigt: I get this warning: `warning C4930: 'std::vector<_Ty> values(std::istream_iterator<_Ty> (__cdecl *)(std::istringstream),std::istream_iterator<_Ty> (__cdecl *)(void))': prototyped function not called (was a variable definition intended?)` and it also doesn't work properly. – LihO Feb 19 '12 at 23:35
  • When I replace `std::vector values(` with `std::vector values = std::vector(`, everything works fine. – LihO Feb 19 '12 at 23:35
  • @LihO: Thanks, I thought most vexing parse was avoided, guess it still found a way to make it look like a function. Re-fixed. – Ben Voigt Feb 19 '12 at 23:37
  • May I make a suggestion that avoids the most vexing parse, and is, IMO, much more readable? http://ideone.com/dUAcD – Benjamin Lindley Feb 19 '12 at 23:43
  • @BenjaminLindley: Yeah, yeah, go ahead and change it. – Ben Voigt Feb 19 '12 at 23:44
  • @BenVoigt: it seems, the constructor taking an initializer list is only taken if the values are convertible to `T`: `std::vector{ 1u, 2u, 3u }` uses `std::initializer_list` while `std::vector{ std::istream_iterator(in), std::istream_iterator() }` uses the constructor taking a pair of iterators. I still need to do some reading in the standard to sort this out for me... – Dietmar Kühl Feb 19 '12 at 23:52
  • @DietmarKühl: most vexing parse could also be avoided by `std::vector( std::istream_iterator{in}, std::istream_iterator{} )` couldn't it? – Ben Voigt Oct 16 '17 at 21:01
6

You could use std::vector for this:

std::vector<int> myVector;

std::string line;
std::getline(std::cin, line);
std::istringstream os(line);

int i;
while(os >> i)
    myVector.push_back(i);

This code requires following includes: <iostream>, <string>, <sstream> and <vector>.

LihO
  • 41,190
  • 11
  • 99
  • 167
  • 2
    Please stop `abusing namepsace std;`. It's a really, really filthy habit, and it ruins the minds of all those newcomers... – Kerrek SB Feb 19 '12 at 23:12
  • I don't think it's quite as bad as Kerrek makes it out to be, but example code should be even more pristine than production code. – Ben Voigt Feb 19 '12 at 23:21
  • @BenVoigt: I know that it is not a good practice and I abuse it really quite a lot especially when I know that I'm going to write more than 5 `std::` prefixes. He made a good thing when he wrote this comment. – LihO Feb 19 '12 at 23:24
  • 1
    @LihO: As long as it`s within a limited scope, `using namespace std;` is fine. The main complaint is related to "action at a distance", which is why it's especially bad to find it in a header file. – Ben Voigt Feb 19 '12 at 23:26
1

Inserters and stream iterators can do this nicely:

#include <iterator>
#include <vector>
#include <iostream>
#include <algorithm>

std::vector<int> numbers;

std::copy(std::istream_iterator<int>(std::cin),
          std::istream_iterator<int>(),
          std::back_inserter(numbers));

Or, as @Ben Voigt has it, construct the vector from the input in one go (if that's an option):

std::vector numbers(std::istream_iterator<int>(std::cin),
                    std::istream_iterator<int>());

You can replace std::cin by a suitable string stream if your input requirements are more complex.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • Boo to `std::copy`, `std::vector` knows how to construct itself from a range. – Ben Voigt Feb 19 '12 at 23:14
  • This neglects the "single line" requirement. – Benjamin Lindley Feb 19 '12 at 23:16
  • What pun? Your code reads the entire standard input stream. The OP only wants a single line. – Benjamin Lindley Feb 19 '12 at 23:19
  • +1 for side-stepping the issue of the most vexing parse by using `std::cin`. Unfortunately, this won't work as easily if the stream is a local variable, though: in this case an extra set of parenthesis is needed. – Dietmar Kühl Feb 19 '12 at 23:25
  • @DietmarKühl: Yeah, we discussed this a while back, where we did everything inside one single `for` loop, using an ad-hoc helper `std::stay` (the opposite of `std::move`). – Kerrek SB Feb 19 '12 at 23:27
  • @DietmarKühl: Ah, [here it is](http://stackoverflow.com/a/8116843/596781). Turns out that `std::stay` makes for good Googlability. – Kerrek SB Feb 19 '12 at 23:29
  • @KerreK: Whole question looks like a dupe at this point, doesn't it? – Ben Voigt Feb 19 '12 at 23:35
  • @BenVoigt: More like a tripe. :-) – Kerrek SB Feb 19 '12 at 23:35
  • @KerrekSB: You don't even need `std::stay()` (not to mention that you aren't allowed to add this to `namespace std` anyway): `std::vector values(std::istream_iterator(std::istringstream(line) >> std::skipws), (std::istream_iterator()));`. – Dietmar Kühl Feb 19 '12 at 23:41