0

I am using getline to fetch characters in buffers from an input file. After reading a line, I loop through all the characters and do a lookup on a map (for some further operations). The problem is that once valid characters are over, my program fetches the eof from the input stream and tries to look for it in the map.

I tried checking inputStream.eof() or eofbit, to see when I reached the end of the stream,but the problem is that both of these get set as soon as I make the final getline(), so I can't use it to determine where the EOF character is located in the input buffer.

How do I identify the EOF character in my input buffer and avoid looking it up in the map?

while(fileInput) {
fileInput.getline(charBuf,charBufSize);

  for(int i=0; i<=charBufSize ;i++) {
    char* currentChar = &(charBuf[i]);
    // do something with currentChar,
    // which I proceed to do by dereferencing currentChar when I need to access
    // the actual character.
  }
}
angryInsomniac
  • 829
  • 2
  • 13
  • 27
  • 1
    You seem to have neglected to post some code which shows the problem you're having. – John Zwinck Dec 26 '11 at 15:55
  • When I post code people resort to "Why did you post so much code" when I don't its the other way around :) – angryInsomniac Dec 26 '11 at 15:57
  • 1
    There is no such thing as "eof character" (except for the SUB control code in Windows in certain contexts), this really needs some code to show how do you interpret that concept. – Cubbi Dec 26 '11 at 16:00
  • possible duplicate of [checking for eof in string::getline](http://stackoverflow.com/questions/2251433/checking-for-eof-in-stringgetline) – Bo Persson Dec 26 '11 at 16:05
  • @BoPersson Its not, I read almost all relevant stuff before posting my query. – angryInsomniac Dec 26 '11 at 16:11
  • 1
    @angry - I believe it is, because you use getline without checking if it worked. That's what the other question is about - checking for eof **after** attempting to read, not before. – Bo Persson Dec 26 '11 at 16:16
  • I agree, this is not a dupe of [checking for eof in string::getline](http://stackoverflow.com/questions/2251433/checking-for-eof-in-stringgetline). Now that I've edited the code sample and question to make them clearer, I hope it should be obvious why it's not a dupe. – Ken Bloom Dec 26 '11 at 16:37
  • Now can we get another upvote around here, so that his score will at least be zero? I don't think this is a bad question -- it was just not very clear the first time. – Ken Bloom Dec 26 '11 at 16:41

3 Answers3

2

There is no "EOF character" in charBuf. Even on systems where EOF character exists as a concept (e.g. MS-DOS and Windows), istream::getline() will not store it in charBuf.

One obvious error in the code posted is the out-of-bounds access in the loop: i<=charBufSize should be i<charBufSize, but to process only the characters obtained by istream::getline, you should use fileInput.gcount() to find out how many characters were actually written to charBuf:

// assuming char charBuf[charBufSize];
fileInput.getline(charBuf, charBufSize);
for(int i=0; i<fileInput.gcount()-1; i++) // -1 if you don't want to process '\0'
{

or just use strings

// assuming std::string charBuf;
getline(fileInput, charBuf);
for(int i=0; i<charBuf.size(); i++)
{
Cubbi
  • 46,567
  • 13
  • 103
  • 169
2

There's no EOF character in C++ that you can check for. What you have to do is get a count of the number of characters read in and use that to know where the file ended. You can get this count using istream::gcount().

You have several problems in your code.

I assume that you've declared

char charBuf[256];
size_t charBufSize = 256;
  1. The first problem is that you're discarding the first line of input. the usual idiom for reading from a file, line by line, is:

    while( fileInput.getLine(charBuf, charBufSize) ) {
      for (...) {  // your for loop is wrong, but I'll get to that in a second
      }
    }
    

    If you really want to discard the first line before you start looping, use

    fileInput.getLine(charBuf, charBufSize); // this first line will be ignored
    while( fileInput.getLine(charBuf, charBufSize) ) {
      for (...) {  // your for loop is wrong, but I'll get to that in a second
      }
    }
    
  2. charBufSize contains the maximum amount of data that could be read, not the actual amount of data read. So if you only read in, say, 12 characters, then you're not only going to perform map lookups on character 13, but you'll also try to process characters 14 thru 256. To avoid this, change your loop to:

    for (int i=0; i < fileInput.gcount(); ++i ) {
      char* currentChar = &(charBuf[i]);
      // do something with currentChar,
      // which I proceed to do by dereferencing currentChar when I need to access
      // the actual character.
    }
    
  3. You're using <= instead of <. I've fixed this in the above code sample.

  4. The whole char* currentChar = &(charBuf[i]); thing is a little unusual. In the code I edited out from your question (so that the basic input question you're asking would be more clear), it seems that you're using it correctly, but it seems that you could just as easily have declared char currentChar = charBuf[i]; made minor changes to avoid having to dereference currentChar in the one place where you use it.

Ken Bloom
  • 57,498
  • 14
  • 111
  • 168
  • Thanks for the vote of confidence and the informative answer :) I now understand why the loop was failing after all the valid characters were over , is because I was looping to the end of the buffersize and not to the actual number of characters read, now I'm using gcount() which seems to resolve the issue (also the <, which was just a silly mistake) However, you said that my loop would ignore the first line of input , while I know that is not the case , i've stepped through it in the debugger and all characters are processed, could you please elaborate this ? – angryInsomniac Dec 27 '11 at 05:42
  • @angryInsomniac: The `getline` command right above the loop reads the first line of your file, but doesn't process it. Then you enter the loop, call `getline` again, which reads the second line of the file, and you start processing from there. – Ken Bloom Dec 27 '11 at 14:28
  • I think that there was some error while copying the code :D There's only one getline in the actual code, I've corrected that in the question as well. – angryInsomniac Dec 27 '11 at 18:30
0

If you want to read line-by-line, then use the standard getline idiom:

std::string line;
while (std::getline(inputFile, line))
{
    // process line
}

If instead you want to read unformatted ("binary") input, use read and gcount:

std::array<char, 4096> buf;
std::streamsize n;
while (true)
{
    inputFile.read(buf.data(), buf.size());

    if ((n = inputFile.gcount()) == 0) { break; }

    // process [buf, buf + n)
}
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084