4

I am a newbie learning C++ to read or write from a file. I searched how to read all contents from a file and got the answer I can use a while loop.

string fileName = "data.txt";
string line ;
ifstream myFile ;
myFile.open(fileName);
while(getline(myFile,line)){
    cout << line << endl;
}

data.txt has three lines of content and output as below.

Line 1
Line 2
Line 3

but if I remove "endl" and only use cout<<line; in the curly bracket of the while loop, the output change to :

 Line 1Line 2Line 3

From my understanding, the while loop was executed 3 times, what's the logic behind it?

einpoklum
  • 118,144
  • 57
  • 340
  • 684
Sean Lau
  • 43
  • 3
  • 1
    Explain to your rubber duck what `endl` *does*. That would be the thing it stops doing when you remove it. – n. m. could be an AI Aug 14 '22 at 07:57
  • 2
    Are you asking why `line` doesn't include the newline character? That's how [`std::getline`](https://en.cppreference.com/w/cpp/string/basic_string/getline) works. – Bob__ Aug 14 '22 at 08:00
  • 2
    This is actually an interesting question, because C's getline [keeps the newline in the result](https://man7.org/linux/man-pages/man3/getline.3.html). – einpoklum Aug 14 '22 at 08:02
  • 2
    and `std::endl` is also a bad idea in most cases. Just use `std::cout << '\n'` – phuclv Aug 14 '22 at 08:34

2 Answers2

2

endl means "end line" and it does two things:

  1. Move the output cursor to the next line.
  2. Flush the output, in case you're writing to a file this means the file will be updated right away.

By removing endl you are writing all the input lines onto a single output line, because you never told cout to go to the next line.

John Zwinck
  • 239,568
  • 38
  • 324
  • 436
  • Hi John, thank you for the answer but it is not what I am asking, I am confused about why the loop was executed 3 times, and how getline() function works in this code. My understanding is when getline() reaches the end of the file it returns false. – Sean Lau Aug 14 '22 at 08:10
  • OK, so if your file has 3 lines in it and you understand that getline gets one line at a time, how many times would you expect the loop to iterate? – John Zwinck Aug 14 '22 at 08:12
  • Yes, I want to confirm if getline gets one line at a time, and returns true to the while loop. Until it reaches the last line and returns true, getline will return false if the file ended. Therefore the loop end. – Sean Lau Aug 14 '22 at 08:17
  • But _why_ does `std::getline()` not keep the line-break/line-feed character? It does so in C. – einpoklum Aug 14 '22 at 08:19
  • 1
    `std::getline()` returns false only when there is no input left. That means it is called four times: the first three times there is data available and it returns true to the while loop. The last time it returns false because the input is exhausted, and so the loop ends. – John Zwinck Aug 14 '22 at 08:25
  • I assume the line-break/line-feed character terminates the line and returns true to the while loop? – Sean Lau Aug 14 '22 at 08:26
  • Yes, the "newline" character ends a line of input and makes `getline()` return true, with the characters before the newline stored in the `string`. – John Zwinck Aug 14 '22 at 08:33
1

Your question regards a semantic ambiguity with std::getline(): Should it result be "a line", in which case the result should include the line-ending newline character, or should the result be the contents of a line, in which case the trailing newline should be dropped?

In the C programming language, getline() takes the first approach:

getline() reads an entire line from stream ... The [result] buffer is null-terminated and includes the newline character, if one was found.

but in C++, the semantics are different: The newline is considered to be a delimiter, and the results of repeated calls to std::getline() is the content without the delimiter. Note that the function actually takes the delimiter in a third parameter, which defaults to '\n', but could be replaced with any other single character. That makes std::getline() more of a tokenizer.

einpoklum
  • 118,144
  • 57
  • 340
  • 684