0

I am working on my assignment and faced a problem with fread() in C++. When I modify the name in my file it modifies it perfectly as I want but the problem occurs when I try to read the file after that, it reads the whole file but it does not stop after that it's running total 146 times whereas there are only 3 names.

My code:-

#include <bits/stdc++.h>
using namespace std;

struct person{
    int id; 
    string fname; 

}s;

void write(){
    FILE *outfile;
    struct person input; 
    int num,ident;
    string sname[] = {"a","b","c"};

    outfile = fopen ("C:\\Users\\Amritesh\\Desktop\\students.txt","wb");

    if (outfile == NULL) 
    { 
        fprintf(stderr, "\nError opend file\n"); 
        exit (1); 
    } 

    scanf("%d",&num);

    for(int i=0;i<num;i++){

        s.fname = sname[i];
        cin >> s.id;

        fwrite (&s, sizeof(s), 1, outfile);
    }
    fclose(outfile);
}

void read(){

    FILE *file1;
    int i=0;
    file1 = fopen ("C:\\Users\\Amritesh\\Desktop\\students.txt","r");

    while(fread(&s, sizeof(s), 1, file1) == 1) {    

        cout << "ID " << s.id << "  Name " <<s.fname << endl;
    }

    fclose (file1); 


} 

void modify(){
    FILE *file;
    file = fopen ("C:\\Users\\Amritesh\\Desktop\\students.txt","r+");

    while(fread(&s, sizeof(s), 1, file)) {

        if(s.fname == "a"){
            s.fname = "d";
            fseek(file,-sizeof(s),SEEK_CUR);
            fwrite (&s, sizeof(s), 1,file);
        }
    }

    fclose (file); 
}

int main(){
    write();
    modify();
    read();
}

Edited code:-

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

using namespace std;

struct person 
{ 
    int id; 
    string fname; 
}s,temp; 



void read() 
{ 
    int num;
    
    ifstream fin;
    fin.open("C:\\Users\\Amritesh\\Desktop\\student.txt",ios::in);
    fin.seekg(0,ios::beg);
    

    //scanf("%d",&num);

    while(fin){

        cout << s.fname << s.id << endl;
    }

    fin.close();
}

void write(){

    int i=0;
    ofstream fout;

    fout.open("C:\\Users\\Amritesh\\Desktop\\student.txt");
    
    
    while(i!=2) {   
        cin >> s.id >> s.fname;
        fout << "ID " << s.id << "  Name " <<s.fname << endl;
        i++;
    }

    
    fout.close();
    
} 

void modify(){

    fstream mod;
    mod.open ("C:\\Users\\Amritesh\\Desktop\\student.txt");
    
    while(mod) {

        if(s.fname == "a"){
            s.fname = "d";
            mod.seekg(-sizeof(s),ios::cur);
            mod << s.fname;
        }
    }

    
    mod.close();
}

int main(){
    
    write();
    read();
    modify();
    
}

Thanks for any answer!

  • 3
    `string` is not a simple data type that you can read/write from a file like you are attempting. – 001 Aug 12 '20 at 11:40
  • 1
    Please take a look at [`size()`](https://en.cppreference.com/w/cpp/string/basic_string/size), and [`c_str()`](https://en.cppreference.com/w/cpp/string/basic_string/c_str) or [`data()`](https://en.cppreference.com/w/cpp/string/basic_string/data), those are the correct ways to get the size/length of an `std::string` and the pointer to it's data. Further more you might want to use `fstream` instead of c functions to read and write files in c++. – t.niese Aug 12 '20 at 11:43
  • 2
    Mandatory reading: [Why should I not `#include `?](https://stackoverflow.com/Questions/31816095/Why-Should-I-Not-Include-Bits-Stdc-H.) – Ted Lyngmo Aug 12 '20 at 11:46
  • 1
    Reading/writing class data from/to files is usually done by adding `operator>>` and `operator<<` overloads for the class. There are plenty of examples of how that's done here on SO. – Ted Lyngmo Aug 12 '20 at 11:47
  • Does this answer your question? [How to write std::string to file?](https://stackoverflow.com/questions/15388041/how-to-write-stdstring-to-file) – 001 Aug 12 '20 at 11:53
  • I don't know what should do I now please answer what changes in code do I now. –  Aug 12 '20 at 12:08
  • @Amritesh I made an [example](https://godbolt.org/z/Ma75dE) using C++ streams and stream operators instead. It should get you started. – Ted Lyngmo Aug 12 '20 at 12:53
  • @TedLyngmo i have edited my code but it doesn't modifies string and also in terminal it's printing same string which i entered last for all inputs but in file it's printing correctly. –  Aug 12 '20 at 15:46
  • please help me with this. –  Aug 12 '20 at 15:46
  • @Amritesh Your `read()` in the edited code doesn't actually read anything. `while(fin)` will make the loop go on for as long as the `fin` stream doesn't have the `badbit` or `failbit` set. You only print the current values of the variables in `s` inside the loop. I guess that must go on indefinitely. In some places it looks like you're only guessing. `fin.seekg(0,ios::beg);` on a newly opened stream isn't necessary for example. Inside `write()` you actually _read_ values from `cin`: `cin >> s.id >> s.fname;` this looks very wrong. Did you look at my example? – Ted Lyngmo Aug 12 '20 at 15:54
  • @TedLyngmo yes, I looked at your example but it seems complex for me to understand . Can you make it easier please. –  Aug 12 '20 at 16:06
  • @Amritesh It's unclear what part of the example that is too complex. Does [this](https://godbolt.org/z/nj54EE) make it easier? – Ted Lyngmo Aug 12 '20 at 16:12
  • @TedLyngmo where you open the file and what is the use of those two operaters I am not able to understand.please guide me –  Aug 12 '20 at 16:53
  • @Amritesh `file` in my example is just a file in memory. (it's a `std::stringstream`) that I write to and read from just as any other `stream`. You can use `ofstream` to open a file for writing and `ifstream` to open a file for reading if you want it written to disk instead. That doesn't change what the `read` and `write` functions do. Like [this](https://godbolt.org/z/5nrbYa). (somewhat simplified and with some error checking) – Ted Lyngmo Aug 12 '20 at 17:20
  • If the example in my latest comment makes sense - [this](https://godbolt.org/z/YcjssE) is how it would look if I made `read` and `write` member functions in the `person` class: – Ted Lyngmo Aug 12 '20 at 17:27
  • 1
    @Amritesh I've now collected my suggestions in an answer instead. I hope you can find a version with a level of complexity that you feel comfortable with and that you can translate that into your own code. – Ted Lyngmo Aug 12 '20 at 17:48

1 Answers1

0

Here are three ideas based on our discussion. I'll start with free functions for reading and writing a person object since it looks like you're at that stage right now. I'll move on to adding member functions in your person class and end with adding stream operators for convenience.

An example of free (non-member) read and write functions:

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

struct person {
    int id; 
    std::string fname; 
};

std::ostream& write(std::ostream& os, const person& p) {
    os << p.id << ',' << p.fname << '\n'; // stream out the properties of a person
    return os; // look at the next example for an alternative doing the same thing
}

std::istream& read(std::istream& is, person& p) {
    // extract "id" and if it succeeds, check if the next char is a , char
    if(is >> p.id && is.peek() == ',') { 
        is.ignore();               // step over the , char
        std::getline(is, p.fname); // read the rest of the line into p.fname
    } else {
        // we didn't get id or the , char, so set the stream in a failed state
        is.setstate(is.failbit);       
    }
    return is;
}

int main() {
    // write to file
    {
        std::ofstream file("C:\\Users\\Amritesh\\Desktop\\student.txt");
        person test1{10, "Foo Bar"};
        person test2{20, "Apa Bepa"};
        write(file, test1);
        write(file, test2);
    }
    // read from file
    {
        std::ifstream file("C:\\Users\\Amritesh\\Desktop\\student.txt");
        person test;

        while(read(file, test)) {
            std::cout << test.fname << '\n';
        }
    }
}

An example of making read and write member functions in person:

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

struct person {
    int id; 
    std::string fname;

    std::ostream& write(std::ostream& os) const {
        // this does the same thing as in the first example
        return os << id << ',' << fname << '\n';        
    }

    std::istream& read(std::istream& is) {
        if(is >> id && is.peek() == ',') {
            is.ignore(); // step over the , char
            std::getline(is, fname);
        } else {
            is.setstate(is.failbit); // we didn't get id or the , char
        }
        return is;
    }    
};

int main() {
    // write to file
    {
        std::ofstream file("C:\\Users\\Amritesh\\Desktop\\student.txt");
        person test1{10, "Foo Bar"};
        person test2{20, "Apa Bepa"};
        test1.write(file);
        test2.write(file);
    }
    // read from file
    {
        std::ifstream file("C:\\Users\\Amritesh\\Desktop\\student.txt");
        person test;

        while(test.read(file)) {
            std::cout << test.fname << '\n';
        }
    }
}

Member functions supported by stream operators:

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

struct person {
    int id; 
    std::string fname;

    std::ostream& write(std::ostream& os) const {
        return os << id << ',' << fname << '\n';        
    }

    std::istream& read(std::istream& is) {
        if(is >> id && is.peek() == ',') {
            is.ignore(); // step over the , char
            std::getline(is, fname);
        } else {
            is.setstate(is.failbit); // we didn't get id or the , char
        }
        return is;
    }    
};

// stream operators calling member functions
std::ostream& operator<<(std::ostream& os, const person& p) { return p.write(os); }
std::istream& operator>>(std::istream& is, person& p) { return p.read(is); }

int main() {
    // write to file
    {
        std::ofstream file("C:\\Users\\Amritesh\\Desktop\\student.txt");
        person test1{10, "Foo Bar"};
        person test2{20, "Apa Bepa"};
        file << test1 << test2;  // calling operator<< for each person object
    }
    // read from file
    {
        std::ifstream file("C:\\Users\\Amritesh\\Desktop\\student.txt");
        person test;

        while(file >> test) {    // extract one person at a time using operator>>
            std::cout << test.fname << '\n';
        }
    }
}
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108