2

How to read an array of integers with unknown length from a file? I don't see a way to get the size of the array, so I tried some temporary-string-stuff, but my code explodes...

any better ideas?

  • 3
    try using `std::vector` or `std::vector` – sgarizvi Jan 04 '13 at 17:56
  • 2
    @GuySirton, http://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong – chris Jan 04 '13 at 17:59
  • 1
    @GuySirton: That's absolutely terrible advice. `eof` is just almost never correct. – Kerrek SB Jan 04 '13 at 18:01
  • @KerrekSB: It's pseudo-code, as is continue doing this until you run out of data. I see your point how this can be wrong/confusing, the point was just to illustrate keep reading and push into a vector while you have something to read (yes the actual code would differ). – Guy Sirton Jan 04 '13 at 18:05
  • As an aside, if the file consists _only_ of integers and you want all of them, you can get the number by getting the file size and dividing by `sizeof(int)`. – Useless Jan 04 '13 at 18:06
  • @Useless Only if the size of an integer in the file is the same as the size of one in your machine. They usually aren't. And of course, there's also no reliable method of getting the file size either. – James Kanze Jan 04 '13 at 18:59
  • @chris It's interesting that in the article you site, the top answers are wrong. You shouldn't use `eof()`, because it is unreliable. It may be set before the input fails, or not, depending on the input you're doing. – James Kanze Jan 04 '13 at 19:04

1 Answers1

8

Use std::vector:

std::ifstream inFile(fileName);

std::vector<int> ints{
    std::istream_iterator<int>(inFile),
    std::istream_iterator<int>()
};

std::vector provides dynamic storage, so it resizes as needed to fit what it holds. All I do is utilize the constructor that takes a pair of iterators and loops through them, beginning to end, and copies the values into the vector. The iterators I'm using will read integers from the file until one can't, as is the case when the end of file is reached. I also use uniform initialization to avoid the most vexing parse, an easy mistake to make when using this form of the constructor.

chris
  • 60,560
  • 13
  • 143
  • 205
  • 4
    This suffers from the most vexing parse. `ints` is a function declaration. – Benjamin Lindley Jan 04 '13 at 18:05
  • @BenjaminLindley, Oops, one second. – chris Jan 04 '13 at 18:05
  • Personally, I've always found this more readable, and less typing: `std::istream_iterator in_begin(inFile), in_end; std::vector ints(in_begin, in_end);` – Benjamin Lindley Jan 04 '13 at 18:06
  • 1
    C++03 MVP elimination: add extra parens around first argument: `std::vector ints((std::istream_iterator(infile)), std::istream_iterator());`. – Jerry Coffin Jan 04 '13 at 18:07
  • @BenjaminLindley, Yeah, that's another option, and it *is* less typing and does avoid running into MVP. And Jerry, Thanks for the C++03 input. That extra set does indeed remove the ambiguity, and is probably the easiest way while retaining the same code structure, as opposed to declaring something beforehand. – chris Jan 04 '13 at 18:11
  • 1
    And `std::ifstream inFile(...);` is also a function declaration. :) – jrok Jan 04 '13 at 18:12
  • @jrok, I appreciate the free laughs, thanks :) Just for you, I made the file stream object declaration valid for use with the vector, assuming `fileName` is declared and is of the right type. – chris Jan 04 '13 at 18:20
  • @JerryCoffin According to the standard, extra parens around any argument will do the trick. At least one compiler blew it, however, if they weren't around the first. (I generally put them around all of the arguments, just for orthogonality.) – James Kanze Jan 04 '13 at 19:01