When i run this code, and open the .dat file in notepad/wordpad it shows some weird characters
#include<iostream>
#include<fstream>
using namespace std;
class Student
{
int rollno;
char name[20];
char div[20];
public:
void accept()
{
cout<<"enter rollno"<<endl;
cin>>rollno;
cout<<"Enter name"<<endl;
cin>>name;
cout<<"Enter div"<<endl;
cin>>div;
}
void write_rec()
{
ofstream f;
f.open("Student.dat",ios::binary|ios::app);
Student s;
s.accept();
f.write((char*)&s,sizeof(s));
f.close();
}
void display()
{
ifstream f;
Student s;
f.open("Student.dat",ios::binary|ios::in);
while(f.read((char*)&s,sizeof(s)))
s.show();
f.close();
}
void show()
{
cout<<rollno<<endl;
cout<<name<<endl;
cout<<div<<endl;
}
};
int main()
{
Student s;
s.write_rec();
s.display();
}
The code is getting compiled and run perfectly but when i open the "Student.dat" file it shows some weird characters
This line:
f.write((char*)&s,sizeof(s));
Is writing the raw binary bytes of your Student object into the file. If that's not the behavior you intended, you'll need to do something else, e.g. translate the member fields of your Student object (in particular the rollno variable, which is an int) into ASCII text strings and write those strings into the file instead.
on both places when you open file:
f.open("Student.dat",ios::binary|ios::app);
and:
f.open("Student.dat",ios::binary|ios::in);
you open as binary. try to remove this option.
as you can see here and here, these are platform specific behaviors.
take a look at this example
EDIT:
and, of course, as Jeremy observed, you have to write meaningful text to your file. on this line:
f.write((char*)&s,sizeof(s));
you are actually writing each byte (as (char*)) of your object. if you understand what you're doing, and that's what you want to observe, than ok. but maybe you should compare both outputs, from this method and from Jeremy's suggestion.
Related
Trying to read a record of students with their name and numbers.
Writing to the file seems fine. However, reading from it prints a never-ending output. The statement - while(!file.eof()) - is causing the problem. But it's how I read the remaining person_details. Your help would be greatly appreciated.
#include <iostream>
#include <fstream>
#include <string>
using std::cin;
using std::cout;
using std::endl;
using std::fstream;
using std::string;
using std::ios;
class telephone
{
protected:
string name;
int number;
public:
void getDetails();
void printDetails() const;
};
void telephone:: getDetails()
{
cout<<"Enter name : "; getline(cin,name);
cout<<"Enter number : ";cin>>number;
}
void telephone:: printDetails() const
{
cout<<"Name : "<<name<<endl;
cout<<"Number : "<<number<<endl;
}
int main(int argc, char const *argv[])
{
telephone person;
fstream file("telefile.txt",ios::in | ios::out | ios::binary | ios::app);
if (!file)
{
cout<<"Invalid file name."<<endl;
return 1;
}
//writing
char choice;
do{
cout<<"----------"<<endl;
cout<<"Person : "<<endl;
cout<<"----------"<<endl;
person.getDetails();
file.write(reinterpret_cast<char*>(&person),sizeof(person));
cout<<"Enter one more?";
cin>>choice;cin.ignore();
}while(choice == 'y');
//reading
file.seekg(0);
file.read(reinterpret_cast<char*>(&person),sizeof(person));
while(!file.eof())
{
cout<<"----------"<<endl;
cout<<"Person : "<<endl;
cout<<"----------"<<endl;
person.printDetails();
file.read(reinterpret_cast<char*>(&person),sizeof(person));
}
return 0;
}
Your basic problem is that you're making a binary image of a std::string object, but a string object doesn't contain the character data, only a pointer to it (this is what allows a string to vary in size). So when you read that pointer back in, you'll start accessing whatever is in that memory location now, not what that memory held when you wrote the file. oops. Even worse things will happen when the string destructor runs and tries to free that pointer.
What you should do instead is write person.name.size() to the file, followed by that many bytes starting at &person.name[0]. Then when you read in the size, you can person.name.resize(size_from_file) and then read that many bytes into &person.name[0].
The Standard actually has a formal name for data types you are allowed to take binary images of: trivially copyable. The requirements are set out in section 9 and your telephone type doesn't meet them:
A trivially copyable class is a class that:
has no non-trivial copy constructors,
has no non-trivial move constructors,
has no non-trivial copy assignment operators,
has no non-trivial move assignment operators, and
has a trivial destructor.
The compiler-generated special member functions for telephone are non-trivial because of the std::string member, so instead of meeting all five requirements, you don't meet any of them.
Everyone has mentioned while (!file.eof()). You're not actually doing it wrong, but there is room for improvement.
First, you can catch more errors using while (file.good()) instead. Right now if you have any failure other than EOF, your loop never terminates, which matches your symptom.
Next, streams have a conversion to bool which is equivalent to calling good(), so you can write while (file). Finally, read like most other stream I/O functions returns the original stream, so you can write
while (file.read(buffer, size))
and avoid duplicating the read call both above and inside the loop.
But you didn't fall into the very common trap of checking eof() before doing the read that actually ran into the end. Bravo for that.
I have basic file handling code of reading file named"student.dat" using visual studio.
the output reads the file and displays the result in console but visual studio pops up the dialog as
code:
#include<iostream>
#include<fstream>
#include<conio.h>
#include<string>
using namespace std;
class student
{
int admno;
// char name[20];
string name;
public:
void getdata()
{
cout<<"\n\nEnter The Name of The Student ";
//gets(name);
cin>>name;
getch();
cout<<"\nEnter The admission no. ";
cin>>admno;
// getch();
}
void showdata()
{
cout<<"\nAdmission no. : "<<admno;
cout<<"\nStudent Name : ";
cout<<name;
//puts(name);
}
int retadmno()
{
return admno;
}
};
int main()
{
student obj;
ifstream fp1;
fp1.open("student.dat",ios::binary);
while(fp1.read((char*)&obj,sizeof(obj)))
{
obj.showdata();
}
fp1.close();
return 0;
}
You are allowed to load raw data only to some POD objects. This line is an error:
fp1.read( (char*)&obj,sizeof(obj) );
because student contains std::string. std::string contains a pointer to a memory block which becomes invalid and totally useless after the object is destroyed. It means the data you load to std::string is just a garbage.
I'd think about object serialization. Boost serialization is a good way to start.
You try to store/load an object to a file, which is invalid.
while(fp1.read((char*)&obj,sizeof(obj)))
Objects may contain references to memory (std::string e.g.) that are invalid after loading. You have to provide serialization for your objects or use plain structs without pointers or references to store your data. E.g.:
struct {
int admno;
char[20] name;
}
If you need strings with variable length, you may use a string store:
struct {
int admno;
size_t name_index;
}
std::vector<std::string> names;
To store, iterate over your names and save length and .c_str of each std::string. To read, do it the other way around and read length into n, read n bytes into a buffer and construct a std::string out of the buffer.
You might have a look at http://www.boost.org/doc/libs/1_55_0/libs/serialization/doc/index.html
You never call GetData so admno is not instantiated in ShowData
//i have two errors in my code
#include <iostream>
#include<iomanip>
#include<fstream>
using namespace std;
struct PLAYER
{
string first_name;
string last_name;
};
void showFile(fstream&, PLAYER&); // line 13
int main()
{
const int MAX=21;
PLAYER array[MAX];
ifstream inputFile;
inputFile.open("PlayerNames.txt",ios::in);
if(inputFile)
{
showFile(inputFile, array); // line 22
}else
cout<<"\n\nError opening file";
inputFile.close();
return 0;
}
void showFile(fstream &file, PLAYER &array )
{
int index=0;
int p_num=1;
string lname, fname;
file>>lname>>fname;
while(!file.eof())
{
// array[index].last_name=
cout<<lname<<" "<<fname;
//array[index].first_name=fname;
//array[index].player_number=p_num;
index++;
p_num++;
file>>lname>>fname;
}
// cout<<"\n"<<index;
//cout<<lname<<" "<<fname;
}
This program worked finally untill i put it in functions.
I have two errors in this program
line 22 error: invalid intialization of reference type std:: fstream
line 13 error: in passing argument 1 of void showFile(std:: fstream&, PLAYER&)
An ifstream can't be converted to an fstream, only an istream.
In the documentation you can see basic_ifstream is derived from basic_istream, not basic_fstream.
Make your function:
void showFile(istream&, PLAYER&);
This is actually better in many ways. For one it's correct (c: But also it means you can test it with any input stream rather than just a file stream. It is more loosely coupled and programs to the more abstract interface.
You function declaration at line 13 shows you are passing 1 PLAYER object, not an array. If you want to stay with arrays, search StackOverflow for "[C++] pass array function".
I highly recommend using std::vector as it has easier syntax when passing to functions.
Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 9 years ago.
Improve this question
I wrote a code that works fine. I just want extra eyes to highlight every thing that should/could be improved. I have to create a student.dat file, and write data (name, age, gpa of each student) given by a user, then close it, and reopen it for reading then, displaying the gpa of students. The Student is a Class object. I just want to check where I am with the notion of OOP (at least with that problem). I am using Dev-C++. The code is below:
#include <iostream>
#include <conio.h>
#include <fstream>
#include <string>
#include <iomanip>
#define W setw
using namespace std;
class Student
{
private:
char name[40];
int age;
double GPA;
public:
Student(){};
void read();
void show(char* ,int ,double );
int writefile(ofstream &OS);
double getgpa(double*, int );
void readfile();
};
void Student::read(void)
{
int nbrSt=0;
cout<<"Please enter the information of the student: "<<endl;
cout<<"'y' to Continue, Ctrl+Z to exit! "<<endl;
cout<<"Name, Age and GPA:\n";
ofstream OS("student.dat", ios::out);
while (cin>>name>>age>>GPA)
{
//writing in the file
writefile(OS);
nbrSt++; //increment the number of students
cout<<"Name, Age and GPA:\n";
}
OS.close();
}
int Student::writefile(ofstream & OS)
{
OS<<'\n'<<W(10)<<name<<W(6)<<age<<W(10)<<GPA;
return 0;
}
void Student::show(char* Name, int Age, double gpa)
{
cout<<'\n'<<W(10)<<Name<<W(6)<<Age<<W(8)<<gpa<<endl;
}
double Student::getgpa(double* allGPA, int nbrgpa)
{
double sum=0;
int i =0;
for ( i=0;i<nbrgpa; i++)
sum+=allGPA[i];
if(nbrgpa>0)
return sum/nbrgpa;
}
void Student::readfile()
{
char Name[30];
int Age;
double aveGPA, gpa;
int nbrgpa=0;
double allGPA[50];
int i=0;
ifstream IS("Student.dat", ios::in);
cout<<"reading from Binary file"<<endl;
if (IS.is_open())
while(IS>>Name>>Age>>gpa)
{
nbrgpa++;
show(Name, Age, gpa);
allGPA[i]=gpa;
i++;
}
IS.close();
aveGPA=getgpa( allGPA, nbrgpa);
cout<<"Average GPA of students: "<<aveGPA<<endl;
}
int main(void)
{
Student S;
S.read();
S.readfile();
return 0;
}
Student(){};
is illegal syntax
Student(){}
is correct.
void Student::read(void)
is badly designed. Student::read should be a method which reads one student. The reading of multiple stduents and the writing of students should be in other functions or methods.
int Student::writefile(ofstream & OS)
should be
int Student::writefile(ostream & OS)
so it works with all kinds of streams (not just file streams). Obviously you should then rename the method. Just call it write for instance.
double Student::getgpa(double* allGPA, int nbrgpa)
should not be a member of Student, it should be a global function.
Your main issue is object-orientated design. You shouldn't just add everything to the Student class without thinking about what you are doing. Methods in the Student class should be about one student, methods that read or write one Student for instance. Everything else should be in global functions (or in other classes if you add a second class to your program).
I just want extra eyes to highlight every thing that should/could be improved.
#define W setw
Don't do that. You may think it makes code using setw look simpler, but other people looking at your code will have to search for what W resolves to.
using namespace std;
Don't declare using namespace std globally. It's not a big problem in small projects, but it makes the code more difficult to reuse.
The interface of your class is non-standard. Consider reading by creating ostream << student operator and reading by creating 'istream >> student'. This respects the rule of least surprise and enables you to (for example) read a sequence of students using iteration.
You need much better function names:
Your read function writes to a file. It would be a big WTF moment for me to see that in production code. Either change the name, or change the functionality.
Your read function is called on a student instance (Student s; s.read();) but it doesn't work on an instance. It in fact transfers/stores a set of records from cin to a file, and sets the instance it is called on, to the last record. If the reading fails half way through the data (i.e. cin>>name>>age>>GPA gets the name correctly but not the age or GPA) it leaves the instance it is called on, in an invalid state.
Consider moving your code from char name[40]; and double* allGPA, int nbrgpa to std::string and std::vector<double> respectively. Using raw data is error-prone and unnecessarily complicated.
There's a lot more to be said, but I think I've given you enough :-).
i am new to c++ and i'm try to write a code that reads integers of a text file and saves each integer in different variables line by line.
I am having problems with the syntax and how to arrange the code. Basically the text file contains 4 integers per line which values are to be read to the a class planet's coordinates and id as shown below. I know the code beloe is incomplete but this is the first time im programming with c++ and need help. please you do not need to explain this using planets or anything. I just need a general understanding
#include <iostream>
#include <fstream>
using namespace std;
class planet{
public :
float x_coordinates;
float y_coordinates;
float z_coordinates;
int id;
};
planet*generate_planet(istream &fin)
{
planet *x= new planet;
fin >> x->id >> x->x_coordinates >> x->y_coordinates >> x->z_coordinates;
return (x);
}
void report_planet( planet &p)
{
cout<<"planet "<<p.id<<" has coordinates (" << p.x_coordinates<<","<< p.y_coordinates<<","<< p.z_coordinates<<")"<<endl;
}
int main()
{
planet p;
planet *x;
ifstream fin("route.txt");
generate_planet(fin);
report_planet(*x);
return 0;
}
You have some errors in your code.
Note that in this line:
fin>>x->id>>x->x_coordinates>>x->y_coordinates>>x->y_coordinates; You write twice to x->y_coordinate instead of x->z_coordinate.
Also, your void report_planet(planet &p) function receives planet & as argument, but you pass it fin which is of time ofstream
Another thing is you're trying to read a file, not write to one, hence the use of ofstream is wrong, you should use ifstream instead.
Does your code even compile?
Good luck.