4

I have some questions regarding using std::ifstream in C++.

Most are general questions I couldn't find answers to, so might be useful for others, too.

Anyways, I use #include <fstream> and made a variable char line[20].

There is a text file that has several lines of the pattern jxxx (where the xs are numbers), like this:

j1234
j5678
j1111
(and so on)

So, I do this:

#include <iostream>
#include <fstream>

char line[20]
ifstream rfile;
rfile.open("path-to-txt-file");
while (!rfile.eof()) {
    rfile.getline(line, 20); (why is 20 needed here?)
    cout >> data >> endl;
    }
rfile.close();

So the concerns are:

  1. why is the number needed in the getline method?

  2. does line have \0 at the end automatically? because when we create char vars like char text[5]; text = "abc1", it is actually saved as "acd1\0" and what happens to the endlines in the file (\n) after each of the jxxx lines? (I would like to use the lines in more complex code than this, so want to know)

  3. Will the program move to the next line automatically? If not, how do I tell it to go to the next line?

Remy Lebeau
  • 454,445
  • 28
  • 366
  • 620
Atem
  • 41
  • 1
  • 1
  • 2
  • 2
    `why is 20 needed here?` because instead of using c++ strings (std::string) you are using c-strings. – drescherjm Oct 12 '17 at 21:41
  • 2
    `while (!rfile.eof()) {` https://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong – drescherjm Oct 12 '17 at 21:42

3 Answers3

12
  1. you are calling std::ifstream::getline(), which takes a char* pointer to a buffer for output. getline() requires you to specify the max size of that buffer so it won't overflow. If you want to handle variable-length lines without worrying about overflows, you should change line to std::string and use std::getline() instead.

  2. if successful, std::ifstream::getline() will null-terminate the output buffer. Which means at most, getline() will read 1 less than the max size requested, so make sure you include room for the null terminator in the size you pass in (getline() may read fewer, if it encounters a line break or EOF). As for the line breaks themselves, they are swallowed by getline(), they will not appear in the buffer.

  3. yes, the code will move to the next line automatically, so you can just keep calling getline() in a loop.

On a side note:

  • while (!rfile.eof()) is bad to use. Use while (rfile) instead. Or better, while (rfile.getline(line, 20)). Either way will account for any errors that occur in both open() and getline(), but the latter ensures that cout is not called if getline() fails.

  • cout >> data >> endl; is also wrong. You need to use << with std::cout, and data should be line instead.

Try this instead:

#include <iostream>
#include <fstream>

char line[20];
std::ifstream rfile;
rfile.open("path-to-txt-file");
if (rfile.is_open()) {
    while (rfile.getline(line, 20)) {
        std::cout << line << std::endl;
    }
    rfile.close();
}

Or this:

#include <iostream>
#include <fstream>
#include <string>

std::string line;
std::ifstream rfile;
rfile.open("path-to-txt-file");
if (rfile.is_open()) {
    while (std::getline(rfile, line)) {
        std::cout << line << std::endl;
    }
    rfile.close();
}
Remy Lebeau
  • 454,445
  • 28
  • 366
  • 620
  • No need to test `if (rfile.is_open())` -- the read will fail if the stream is not open. And there's no need to close the file; the destructor will do that. – Pete Becker Oct 12 '17 at 21:57
  • @PeteBecker: I'm aware of that. The OP's question calls `close()` explicitly, so it makes sense to check `is_open()` to bypass the rest of the code if `open()` fails. Yes, the `ifstream` destructor closes the file, but not until the `ifstream` goes out of scope. Users are allowed to explicitly `close()` before that time. Maybe there is more code after the file is read from, keeping the `ifstream` in scope for a longer time. Best to `close()` it when done with the file (personally, I would wrap the `ifstream` in its own scope in that situation). I don't make assumptions in my answer. – Remy Lebeau Oct 12 '17 at 21:59
0
  1. The number you are providing there is the maximum number of char to read.
  2. The final character in ifstream.getline, which you are using, is a \0
  3. It will return at either when the number of chars is reached or a newline

It sounds like you want the getline function that would be used like getline( stream, &string, delemiter ), so in your case

std::string buff;
getline( rfile, buff )

This will read the file until a newline is found and store the string, minus the newline, in buff

Beached
  • 1,446
  • 13
  • 16
0
  1. getline() function takes a pointer to char as a parameter, it has no way to know how big the array is, that's why you have to pass the number yourself, otherwise it could try to read chars into memory "outside" of the array.

See Passing arrays to function in C++

  1. Char arrays are not null terminated by default, they must be done so explicitly (like getline() will do here), but you need it only if you want to use your char array as a string. This way you can write some function that takes char* as parameter without additional one with the size of the array, you will know where the end of the string is when you encounter 0 even if the caller doesn't pass the size of it like you would for getline() in your code. This is pretty much the idea behind c-style string.
Murzinio
  • 94
  • 1
  • 3