简体   繁体   中英

C++ getline function missing the first line of txt file

I have written a function to read from.txt file and build a linked list, but the function missed the first line of the file. Anyone have any idea why that happens?

output:

//empty line  
gmail  
San Francisco  
123456

.txt file

person1
gmail
San Francisco
123456

readFile function

void list::readFile(std::string fileName){
    fstream fs;
    string dummy = "";
    string firstline;
    record * previous = new record;
    record * temp = new record;
    int recordCount = 0;
    fs.open(fileName, ios::in | ios::binary);
        do{
            std::getline(fs, temp->name);
            std::getline(fs, temp->email);
            std::getline(fs, temp->address);
            fs >> temp->phoneNo;
            std::getline(fs, dummy);
            recordCount++;

            if(head == NULL){
                head = temp;
                previous = temp;
                tail = temp;
            } else {
                previous->next = temp;
                previous = temp;
                tail = temp;
            }

        } while(!fs.eof());
    // } else {
    //     cout << "there's no record in the file yet." << endl;
    // }

    cout << head->name << endl;
    cout << head->address <<endl;
    cout << head->email << endl;
    cout << head->phoneNo << endl;
}

You create a single node so every iteration through the loop you overwrite the previously read values.

In the second iteration of the while loop your first call to getline presumably fails and sets the value of name to an empty string. As the stream is now in a failed state the rest of your reads are ignored and finally the loop breaks at the end of the loop.

This might be closer to what you wanted:

    int recordCount = 0;
    fs.open(fileName, ios::in | ios::binary);
        while(fs) {
            record * temp = new record;
            std::getline(fs, temp->name);
            std::getline(fs, temp->email);
            std::getline(fs, temp->address);
            fs >> temp->phoneNo;
            if (!fs) {
                // Reading failed, delete the temporary and exit the loop
                delete temp;
                break;
            }
            std::getline(fs, dummy);
            recordCount++;

            if(head == NULL){
                head = temp;
                previous = temp;
                tail = temp;
            } else {
                previous->next = temp;
                previous = temp;
                tail = temp;
            }

        }

Your code could be made memory leak safer by using smart pointers to ensure temp is never leaked even if exceptions are thrown.

I will explain to you why this problems happens and how it can be avoided.

It is a typical problem, mentioned thousands of times in comments, also above by "molbdnilo".

You must not use while (fs.eof()) .

I will explain to you why. By the way, it only happens, because you have a new line at the end of the last line.

Let us see what happens:

  1. The variable "temp" is allocated one time
  2. The file is opened
  3. The do -loop starts
  4. You read the name, email, address via the unformatted input function std::getline . This function will eat up the trailing white space '\n' (but not cope it to the read variable
  5. You use the formatted input function >> for reading the phone number (This is not a good idea. Anyway). The formatted input function will stop at a white space, here the '\n' at the end of the last line. It will not consume the '\n'. This is still in the stream and wating for input.
  6. You use std::getline with a dunmmy, to read the still existing '\n' from the stream. The stream is still OK. Everything went well so far. The file is also not at EOF. We could read everything. So, fine.
  7. End of do loop . You say: while(.fs.eof()) . But as said above: There is not yet an EOF. Everything was and still is OK. The loop will continue.
  8. Back at the start of loop again
  9. std::getline(fs, temp->name); will be called. And now and not before, we get an EOF. because we tried to read and now there is nothing more to read. "temp->name" will be set to an emptry string. And now, input stream is in condition EOF. 10 All further reads will do nothing, because the stream is in EOF. The variables will not be modified from now on.

That is the reason why, name is empty and the other data is still there from the last loop run.

For a quickfix you could write

void list::readFile(std::string fileName) {
    fstream fs;
    string dummy = "";
    string firstline;
    record* previous = new record;
    record* temp = new record;
    int recordCount = 0;
    fs.open(fileName, ios::in | ios::binary);
    if (fs) 
    while (std::getline(fs, dummy)) {
        temp->name = dummy;
        std::getline(fs, temp->email);
        std::getline(fs, temp->address);
        fs >> temp->phoneNo;
        std::getline(fs, dummy);
        recordCount++;

        if (head == NULL) {
            head = temp;
            previous = temp;
            tail = temp;
        }
        else {
            previous->next = temp;
            previous = temp;
            tail = temp;
        }

    } 
    // } else {
    //     cout << "there's no record in the file yet." << endl;
    // }

    cout << head->name << endl;
    cout << head->address << endl;
    cout << head->email << endl;
    cout << head->phoneNo << endl;
}

But this is also not good. I will show a better solution later.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM