0

Hi everyone quick c++ question. I have a file that is formatted in a special way. The first line is a person's first and last name, the second line is his phone number and the third is adress. this a peace of the file, it's much larger but it looks like this:

Mans Hansson

8510309159

Bössgränd 90, 373 02 RAMDALA

Olliver Lindberg

8602024898

Sandviken 76, 710 27 DYLTABRUK

Eskil Johnsson7901105838

Löberöd 29, 521 29 KÄTTLISTORP

And basically I want to read the first three lines once at a time. What I mean is I want to read line one and store in a variable called name, line 2 in phone_number and line 3 in adress and then repeat until end of file. this is my code:

int main(){
    fstream fs; 
    fs.open("/Users/brah79/Downloads/skola/c++/OOP/uppgift1/personInfo.txt"); 
    string name; 
    string phone_number; 
    string adress;
    while(!fs.eof()){
       for(int i = 0; i < 3; i++){
        getline(fs, name); 
        getline(fs, phone_number); 
        getline(fs, adress); 
       }
       cout << "first name: " << name << endl; 
       cout << "person nummer: " << phone_number << endl; 
       cout << "adress: " << adress << endl; 
    }


    fs.close(); 



    return 0; 
}

this is the output:

first name: Eskil Johnsson

phone number: 7901105838

adress: Löberöd 29, 521 29 KÄTTLISTORP

question 1: my code is only reading the last three lines so basically information about the last person only.

question 2: the name of the person consists of first and last name and I could not figure out a way to separate them into 2 variables.

Hope my question is clear and someone can help.

brah79
  • 37
  • 5
  • Please think about the loop `for(int i = 0; i < 3; i++)` and what it does. Explain it to your [rubber duck](https://en.wikipedia.org/wiki/Rubber_duck_debugging). – Some programmer dude Nov 08 '22 at 10:56
  • Also: [Why is iostream::eof inside a loop condition (i.e. `while (!stream.eof())`) considered wrong?](https://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-i-e-while-stream-eof-cons) – Some programmer dude Nov 08 '22 at 10:56
  • Okey so this is how I was thinking: for(int i = 0; i < 3; i++) // read the first three line and then check if we reached the end of the file if not read the next three line ex... and that what the while loop is doing – brah79 Nov 08 '22 at 11:02
  • Note that inside the `for` loop you have *three* calls to `std::getline`. So the `for` loop will attempt to read nine (3 * 3) lines in total, before you print the last three lines and the `while` loop continues. You don't need that `for` loop, just the three `std::getline` calls. – Some programmer dude Nov 08 '22 at 11:11
  • I removed the for loop and it worked but I still don't understand why tbh. Can you please explain why my logic is wrong. – brah79 Nov 08 '22 at 11:16
  • it's c++ not c sir so I guess can't use fscanf() unless I'm missing something haha – brah79 Nov 08 '22 at 11:18
  • You have three records in your file. Each record is three lines. The three calls to `std::getline` will together read *one* record. The `for` loop will read three records. Once the `for` loop is finished, only the last record will be in your variables, and you print that. Then the `while` loop continues, but `eof` will not be true, and you do your `for` loop again but this time all three `std::getline` calls fail, leaving the strings unmodified. You do that three times in the `for` loop, and again print the last record. Then the `while` loop breaks. – Some programmer dude Nov 08 '22 at 11:19
  • ahaaaa okey alright I totally understand now and it makes since. based on this explination I tried part 2 of the question. I wanted to separate the first line into first and last name it didn't completely work. this is the code: string first_name; string last_name; string phone_number; string adress; while(!fs.eof()){ fs >> first_name; fs >> last_name; getline(fs, phone_number); getline(fs, adress); and this is the output: first name: Mans last name: Hansson phone number: adress: 8510309159 – brah79 Nov 08 '22 at 11:27

2 Answers2

0

Try using fscanf(). It allows you to read formatted inputs from files. Use the value returned from the function to check if you are reading the name, the phone number or the address. If the input is always consistent (name followed by phone number followed by address) you need to change how you call fscanf().

Arda
  • 1
  • 3
  • Not that this is wrong or anything, it's a very C thing to do, and isn't needed for C++ which has other mechanisms. – ChrisMM Nov 08 '22 at 14:45
0

For a simple way to understand what's happening, lets unroll the for loop (that means we do all the statements in the loop separately).

That will give us this code:

while(!fs.eof()){
    // First iteration of the for loop
    getline(fs, name); 
    getline(fs, phone_number); 
    getline(fs, adress); 

    // Second iteration of the for loop
    getline(fs, name); 
    getline(fs, phone_number); 
    getline(fs, adress); 

    // Third iteration of the for loop
    getline(fs, name); 
    getline(fs, phone_number); 
    getline(fs, adress); 

    cout << "first name: " << name << endl; 
    cout << "person nummer: " << phone_number << endl; 
    cout << "adress: " << adress << endl; 
}

From this it will be easy to see that you discard the data you read in the first and second iteration of the for loop.

It's also possible to see that you read the whole file (assuming it's only three records) in the first iteration of the while loop.


The correct code, without the for loop and without the bad while loop condition, it should instead be something like this:

// Read three lines, until reaching EOF or an error
while(getline(fs, name) &&
      getline(fs, phone_number) &&
      getline(fs, adress))
{
    // Print the three lines we just read
    cout << "first name: " << name << endl; 
    cout << "person nummer: " << phone_number << endl; 
    cout << "adress: " << adress << endl; 
}
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Waaw thank you sir. Can you please help with part of the question also? – brah79 Nov 08 '22 at 11:37
  • @brah79 That's a different problem, and should really be asked as a different question, *but* I'll give you a hint: I assume you know how to read strings using `std::cin` and the stream extraction operator `>>`? Like `std::cin >> first_name;`? Then I recommend that you learn about [`std::istringstream`](https://en.cppreference.com/w/cpp/io/basic_istringstream/basic_istringstream), which is an input stream like `std::cin`, but for strings. Put your `name` into an input string stream, and get the names like you would from `std::cin`. Lycka till! – Some programmer dude Nov 08 '22 at 11:42
  • @ArminMontigny It's a start at least. One thing at a time. – Some programmer dude Nov 08 '22 at 13:12