Question about getline with fstream

  • Thread starter yungman
  • Start date
  • #51
5,100
124
@yungman ##-## have you fully considered the fact that C++ is a strictly-typed language? That fact has important implications and consequences. Please read up on them.
What do you mean typed language?
 
  • #52
1,733
1,002
What do you mean typed language?
I mean that when you pass values, the 'type' of the value, for example 'character', is enforced ##-## if you try to do an arithmetic operation on character data your program will fail ##-## e.g. you can't multiply L by M :wink:
 
  • Like
Likes yungman
  • #53
34,315
5,954
I believe in the original program, michael is being read twice. It just using struct, there must be something that cause the eof() to stay as 0 after reading michael the first time.
The original program was using read() to do the extraction from the file. The behavior with eof() has nothing to do with the string being in a struct.

And no, the string "michael" is NOT read twice.

I change to run the program in TEXT file instead of binary file. RESULT IS EXACTLY THE SAME. There is no difference between text and binary file.
I KNOW what you said before, I am not convinced, see the post I reply to Jarvis. I don't think the book will ignore this if that is true. I think some else is going on.
What's going on is that read() extracts a specific number of bytes, and the extraction operator >> extracts characters of a string until it reaches the null character.
Something is inconsistent in this eof(), I just don't have the knowledge to dig deeper, so it's best to get on with this, put in my cheat sheet and hurry up to get onto Chapter 13 Classes.
What's the rush? Skipping over things you don't understand will almost certainly come back to bite you in the butt. And "hurrying up" has caused many problems for you in the past couple of months.

I'll grant you that checking for eof() is tricky. It's more complicated due to several factors -- whether the file is being read in text mode or binary mode, and whether you're doing the reading with read() or with the extraction operator >>. If a read() encounters the end of the file before the specified number of bytes, eof() will return true. Otherwise it will be false. If you're extracting a string from a file, >> won't extract the null character at the end of the string.

In the program below, I create a file in binary mode, and write the C-string "cats" and a single byte, 'A'.
The contents of the file are the ASCII codes for 'c' 'a' 't' 's' '\0' 'A'.
I get different behavior if I then open the file for input in binary mode, or if I open it for input in text mode.
BTW, if you are going to read a file in binary mode, you should use read(), not >>.

When I open the file for reading in binary mode, I read() 5 bytes, the four alpha characters and the null.

When I open the file for reading in text mode, the insertion operator gets the four alpha characters, but leaves the null character in the file. I've looked at the VS docs and cplusplus.com, but I don't know what the actual mechanism is -- if the null is not read, or if it's read but inserted back in the file.

Here's an example.
C++:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{      
    char testStr[] = "cats";
    char num = 65;
    char val;
    char testStr2[5];
    char testStr3[5];
    char ch;
    fstream testFile;

    testFile.open("demofile.txt", ios::out|ios::binary);
    cout << " Writing the string \"cats\"" <<" and a byte to file.\n";
    testFile.write(testStr, sizeof(testStr));
    testFile.write((char*)&num, sizeof(num));
    testFile.close(); 
    

    testFile.open("demofile.txt", ios::in|ios::binary);
    cout << " Read file in binary mode using read(). \n";
    testFile.read(testStr2, sizeof(testStr2));
    testFile.read((char*)&val, sizeof(val));
    cout << " String:  " << testStr2 << " and value: " << val << "\n";
    cout << " testFile.eof() = " << testFile.eof() << "\n";
    ch = testFile.get();
    cout << " After get(), testFile.eof() = " << testFile.eof() << "\n\n";
    testFile.close();
    testFile.clear(0);   // Clear all flags - eofbit, failbit, badbit

    ch = 'Z';
    val = 0x7F;
    testFile.open("demoFile.txt", ios::in);
    cout << " Read file in text mode using extraction operator. \n";
    testFile >> testStr3;
    testFile >> ch;
    cout << " After extracting ch, testFile.eof() = " << testFile.eof() << "\n";
    testFile >> val;
    cout << " After extracting val, testFile.eof() = " << testFile.eof() << "\n";
    cout << " String: " << testStr3 << " and value: " << val << "\n";
    ch = testFile.get();
    cout << " After get(), testFile.eof() = " << testFile.eof() << "\n";
    testFile.close();
}
The output from the above. I've added comments to explain why something happened, but otherwise the output is as I saw it.
Code:
 Writing "cats" and a byte to file.
 Read file in binary mode using read().
 String:  cats, value: A                // Both values are read
 testFile.eof() = 0                         // After read() of the string, and read() of the byte, we're not at end of file
 After get(), testFile.eof() = 1    // One more read, using get() and eof() is true

 Read file in text mode using extraction operator.
 After extracting ch, testFile.eof() = 0           // String extracted, and null (ch - with value '\0') extracted - no eof. 
 After extracting val, testFile.eof() = 0          // val extracted - no eof.
 String: cats, value: A                                     // Both values are read
 After get(), testFile.eof() = 1             // Final read, using get() and eof() is true.
 
  • Like
Likes Jarvis323, pbuk, yungman and 1 other person
  • #54
1,733
1,002
@Mark44 back in the day ('70s) IBM advised us to if we were reading whole card pictures (80-characters) and writing whole (133 column green-bar paper) line-printer print lines use GETLINE and PUTLINE, instead of TGET and TPUT, presumably for the sake of efficiency, even though TGET and TPUT, despite having been written for the Teletype (TTY 110) terminal, could read and write from and to anywhere.
 
  • #55
5,100
124
.................
What's going on is that read() extracts a specific number of bytes, and the extraction operator >> extracts characters of a string until it reaches the null character.
What's the rush? Skipping over things you don't understand will almost certainly come back to bite you in the butt. And "hurrying up" has caused many problems for you in the past couple of months.

I'll grant you that checking for eof() is tricky. It's more complicated due to several factors -- whether the file is being read in text mode or binary mode, and whether you're doing the reading with read() or with the extraction operator >>. If a read() encounters the end of the file before the specified number of bytes, eof() will return true. Otherwise it will be false. If you're extracting a string from a file, >> won't extract the null character at the end of the string.

....................................................
Thanks a million!!
I think this is the first time it makes sense to me.

Let me repeat back to you to confirm. read() reads VERY SPECIFIC number of bytes according the datatype that it's supposed to read. If read() gets the correct number of bytes, it's happy, eof() remain 0. This means when it reads michael, it GOT the correct number of bytes and left eof()=0. It's ONLY it the next read that it is not getting the bytes as it's the end already, then eof() is changed to 1.

I have a question, name has different length, how does read() know when it has enough bytes. Does it look for a character to know it's complete?

Now this make a world of sense. Please let me know whether I am right or not.

Thanks

As for why am I rushing, I always set goals, I am very goal oriented, I set my goal to finish this chapter in less than 2 weeks, because of reinterpret_cast, I spent two days, and I spent two days on this. That's why I am kind of want to move on. A lot of times I notice the book throw out something without explaining, it must be the author think it's better to use it and explain more when the time is right. It's like if the book tries to explain what is datatype, object, instance before letting student just define int x = 5 in chapter 1, we'd never get through chapter one. In fact, that's how I felt when I asked a question here, you guys explained and it's like Russian to me. Took me till lately that I understand datatype and all on int x = 5!!!
 
  • #56
34,315
5,954
Nobody responded to your code in post #47 and your comments.
You would think for files, eof() means the same thing. I've been doing more experiments:
C++:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main()
{
    char name[100];
    fstream people;
    people.open("people.dat", ios::out | ios::binary);
    people << "alan ";
    people << "Paul ";
    people << "john ";
    people << "michael";
    people.close();

    people.open("people.dat", ios::in | ios::binary);
    do
    {
        people >> name;
        cout << " Name: " << name << "   !people.eof() = " << !people.eof() << "\n";
    } while (!people.eof());
    people.close();
}
First, I have to put a space after each name to separate them or else they will be alanPauljohnmichael upon the first read and !people.eof()=0;
No, you put a space after the first three names, but not the fourth.
In the loop that reads from the file, the first three names are extracted with no problems, but the fourth extraction fails, because the >> operator extracts m i c h a e l, and keeps extracting, thus causing eof() to be true.
A very simple fix is to add a trailing space on the string "michael ". Then all four names are extracted from the file, and the next extraction fails with eof() becoming true.
 
  • Like
Likes sysprog
  • #58
1,733
1,002
@Mark44 I plead overlap - I would have let your post #56 suffice, had I read it before posting my #57 - Regards -
 
  • #59
34,315
5,954
Let me repeat back to you to confirm. read() reads VERY SPECIFIC number of bytes according the datatype that it's supposed to read. If read() gets the correct number of bytes, it's happy, eof() remain 0. This means when it reads michael, it GOT the correct number of bytes and left eof()=0. It's ONLY it the next read that it is not getting the bytes as it's the end already, then eof() is changed to 1.
No, it's not according to the datatype that will be read -- it's according to the number of bytes that are supposed to be read. If the call to read() indicates that N bytes should be read, and read processes N bytes, then eof() is false. If read() is able to read only M bytes, where M < N, the eof() returns true.
For example,
C++:
testFile.read(testStr2, sizeof(testStr2));
Here testStr2 is declared as an array of type char, with 5 bytes. Notice that I don't need a cast of any kind, because testStr2 is already a char pointer. The 2nd argument says to process 5 bytes. As long as there are 5 bytes left in the file, eof() will be false.
I have a question, name has different length, how does read() know when it has enough bytes. Does it look for a character to know it's complete?
The 2nd argument to read() is the number of bytes to read.
As for why am I rushing, I always set goals, I am very goal oriented, I set my goal to finish this chapter in less than 2 weeks, because of reinterpret_cast, I spent two days, and I spent two days on this.
Goals are based on plans, and plans are subject to some events that are difficult to forecast correctly. When that happens, the wise thing to do is to reassess the plans and possibly adjust the timeline for the goals.
 
  • Like
Likes sysprog and yungman
  • #60
phinds
Science Advisor
Insights Author
Gold Member
2019 Award
16,551
6,918
As for why am I rushing, I always set goals, I am very goal oriented, I set my goal ...
And does it ever happen that it turns out that your goals are unrealistic and you have to do an inadequate and rushed job to meet them instead of just taking longer and doing a good job? Maybe you set the wrong goal. You set a TIME goal. Why not set a LEARNING goal instead?
 
  • Like
Likes sysprog and Vanadium 50
  • #61
Vanadium 50
Staff Emeritus
Science Advisor
Education Advisor
2019 Award
25,709
8,901
You set a TIME goal. Why not set a LEARNING goal instead?
A time goal without a learning goal can be met just by waiting.
 
  • Like
Likes sysprog
  • #62
phinds
Science Advisor
Insights Author
Gold Member
2019 Award
16,551
6,918
A time goal without a learning goal can be met just by waiting.
Yeah, but he's setting very brief time goals.
 
  • #63
Vanadium 50
Staff Emeritus
Science Advisor
Education Advisor
2019 Award
25,709
8,901
All the faster. :wink:
 
  • Haha
Likes phinds
  • #64
Vanadium 50
Staff Emeritus
Science Advisor
Education Advisor
2019 Award
25,709
8,901
There's the old line "I took a speed-reading class and was able to read War & Peace in twenty minutes. It's about Russia."
 
  • Haha
Likes sysprog
  • #65
phinds
Science Advisor
Insights Author
Gold Member
2019 Award
16,551
6,918
There's the old line "I took a speed-reading class and was able to read War & Peace in twenty minutes. It's about Russia."
Reminds me of:
1601298941329.png
 
  • Haha
Likes sysprog
  • #66
34,315
5,954
The question about how file input works has been beaten to death, so this seems like a good place to end the thread.
 

Related Threads on Question about getline with fstream

  • Last Post
Replies
0
Views
2K
  • Last Post
Replies
17
Views
10K
Replies
9
Views
20K
Top