when i run this code everything goes fine when writing , but when i press 2 to read it goes well and read everything just fine but when it it finishes reading the file (show function) it pops up a problem says " Unhandled exception at 0x5DF9CCC8 " with break , continue options .
from my searching i think the problem comes from a pointer points to Null , but i don't know how to resolve it .
here is the code
class person{
public :
string name;
int id ;
int age ;
void person :: show();
void person :: add_menue();
void person :: insert_data();
void person :: show_data();
};
person personobject;
void person :: add_menue()
{
cout << "Please Enter Name ID Age :" << endl;
cin >> name >> id >> age ;
}
ofstream file;
void person::show()
{
cout<<"Age => "<<age<<endl;
cout<<"Name => "<<name<<endl;
cout<<"ID => "<<id<<endl;
}
void person :: insert_data()
{
ofstream file;
file.open("binary.dat",ios::app| ios::binary);
personobject.add_menue();
file.write((char*)&personobject, sizeof(personobject));
file.close();
}
void person :: show_data()
{
ifstream file;
file.open("binary.dat",ios::in| ios::binary);
if(!file)
{
cout<<"File not Found";
}
else
{
file.read((char*)&personobject, sizeof(personobject));
while(!file.eof())
{
personobject.show();
cout<<"Press Any Key....For Next Record"<<endl;
getchar();
file.read((char*)&personobject, sizeof(personobject));
}
}
file.close();
}
void main ()
{
int choice;
cout << "1 - to write \n2 - to read" << endl;
cin >> choice;
if (choice==1)
{
person f;
f.insert_data();
}
if (choice==2)
{
person a;
a.show_data();
system ("pause");
}
}
Because you are using a string object instead of a plain character array, you can't just type cast the whole class to a char* and write it to the file (which in itself is a poor way of doing it. What if you changed around the order of the parameters and tried loading an older file?).
In your insert_data function, write each variable individually instead of casting the entire class. You could write the age and id first and you know that would take up 8 bytes, so whatever is remaining is the size of the name which can be loaded back into the string object in your read_data function.
Related
I created a simple bank application program to ask a user whether they want to add a bank record to a file or show all the records available. Both these functions are facilitated by write_rec() and read_rec() respectively. But when the function read_rec() is applied, while it does print all the records available in the file(a single file is used to store all the records), for some reason it prints the last record in the file two times instead of just once. It's very frustrating to see everything works so well then this problem pops up out of nowhere. I tried to see where the issue is but for the life of me I just can't find it. Can you guys please help me with this one?
Here's the code:
#include<iostream>
#include<fstream>
#include<cstdlib>
using namespace std;
class account_query
{
char account_number[20];
char firstName[10];
char lastName[10];
float total_Balance;
public:
void set_data();
void show_data();
void write_rec();
void read_rec();
};
void account_query::set_data()
{
cout<<"\nEnter Account Number: ";
cin>>account_number;
cout<<"Enter First Name: ";
cin>>firstName;
cout<<"Enter Last Name: ";
cin>>lastName;
cout<<"Enter Balance: ";
cin>>total_Balance;
cout<<endl;
}
void account_query::show_data()
{
cout<<"Account Number: "<<account_number<<endl;
cout<<"First Name: "<<firstName<<endl;
cout<<"Last Name: "<<lastName<<endl;
cout<<"Current Balance: Rs. "<<total_Balance<<endl;
cout<<"-------------------------------"<<endl;
}
void account_query::write_rec()
{
ofstream outfile;
outfile.open("D:/rec.bin", ios::binary|ios::in|ios::out|ios::app);
set_data();
outfile.write(reinterpret_cast<char *>(this), sizeof(*this));
outfile.close();
}
void account_query::read_rec()
{
ifstream outfile;
outfile.open("D:/rec.bin", ios::binary);
if(!outfile.is_open())
{
cout << "Error! File not found!" << endl;
return;
}
cout << "\n****Data from file****" << endl;
while(outfile.good())
{
outfile.read(reinterpret_cast<char *>(this), sizeof(*this));
show_data();
}
outfile.close();
}
int main()
{
account_query A;
int choice;
cout << "***Account Information System***" << endl;
while(true)
{
cout << "Select one option below";
cout << "\n\t1-->Add record to file";
cout << "\n\t2-->Show record from file";
cout << "\n\t3-->Quit";
cout << "\nEnter you chice: ";
cin >> choice;
switch(choice)
{
case 1:
A.write_rec();
break;
case 2:
A.read_rec();
break;
case 3:
exit(0);
break;
default:
cout << "\nEnter correct choice";
exit(0);
}
}
system("pause");
return 0;
}
And this is the result I get when I try to print the record on the console:
Please help me 🥺
As already pointed out in the comments section, the problem is that the line
while(outfile.good())
will only check whether the stream extraction has already failed. It will not tell you whether the next stream extraction operation will fail or not. It is unable to provide this information.
Therefore, you must check the state of the stream after the attempted stream extraction operation, to see whether it succeeded or not. So you must check the stream state after this line:
outfile.read(reinterpret_cast<char *>(this), sizeof(*this));
It should be checked before you call show_data, because you don't want to call show_data if the stream extraction failed.
The simplest fix would be to change the lines
while(outfile.good())
{
outfile.read(reinterpret_cast<char *>(this), sizeof(*this));
show_data();
}
to the following:
while( outfile.read(reinterpret_cast<char *>(this), sizeof(*this) ) )
{
show_data();
}
This will work because istream::read will return a reference to the stream object outfile and writing
while ( outfile )
is equivalent to
while ( !outfile.fail() )
due to istream::operator bool being called.
I am learning c++ and have a trouble in file handling. I am writing a code as a homework where i have to write objects into a file and then read those objects as array from the file at once. Here is my code:
#include <iostream>
#include <fstream>
using namespace std;
class Records{
char* name;
int roll;
public:
Records()
{
name = new char[20];
}
void setData()
{
cout<<"Enter name: "<<endl;
cin>>name;
cout<<"Enter roll"<<endl;
cin>>roll;
}
char* getname()
{
return name;
}
int getRoll()
{
return roll;
}
void operator = (Records& no)
{
name = no.name;
roll = no.roll;
}
};
int main()
{
int i =0 ;
Records rec;
rec.setData();
Records::increase();
ofstream fout;
fout.open("file.txt", ios::app);
fout.write((char*)&rec, sizeof(rec));
fout.close();
Records* results = new Records[20];
Records rec1;
ifstream fin;
fin.open("file.txt", ios::in);
while(!fin.eof())
{
fin.read((char*)&rec1, sizeof(rec1));
results[i] = rec1;
i++;
}
fin.close();
cout<<results[0].getRoll();
return 0;
}
So basically, I made a Records class and store its object in a file. That works fine but I faced problem while taking data from file. It is not showing anything or sometimes showing garbage value. Anyone have better idea please hep me.
Thanks in advance!
First, you have to open file in binary mode for read and write.
std::ofstream fou("out_filename",std::ofstream::binary);
std::ifstream fin("in_filename", std::ifstream::binary);
Secondly, you assign operator=() is problematical. It assigns two records using the same address. Therefore in the reading process, all 20 elements in result[i] were all sharing the address of rec1::name. You have to correct the operator=() by copying contents of name.
This is not good.
void operator = (Records& no)
{
name = no.name;
roll = no.roll;
}
Rewrite as follows:
Edit: since your objects are all initially assigned with its memory. The new allocation is not necessary.
Records& Records::operator=(const Records& no)
{
// this->name = new char [20];
std::copy_n(no.name, 20, this->name); // include <algorithm>
roll = no.roll;
return *this; // return current object for another =.
}
Finally, add a destructor
Records::~Records() {
delete [] this->name; }
Good luck!
After fixed some other errors, I post this final version for you reference. Note that this project cannot use dynamic allocation for the field "name". Using dynamic allocation, the 20-byte of "name" is not counted as the size of class Records, and the pointer itself is not transferable. It causes read/write error in the field "name".
#include <iostream>
#include <fstream>
#include <algorithm>
using namespace std;
class Records{
char name[20];
int roll;
public:
Records()
{
// name = new char[20];
}
void setData()
{
cout<<"Enter name: "<<endl;
cin>>name;
cout<<"Enter roll"<<endl;
cin>>roll;
}
const char* getname() const
{
return name;
}
int getRoll() const
{
return roll;
}
Records& operator = (const Records& no)
{
std::copy_n(no.name, 20, this->name);
roll = no.roll;
return *this;
}
};
int main()
{
int i =0, c ;
std::string a;
Records rec;
ofstream fout;
fout.open("file.txt", std::ofstream::binary);
c = 0;
while (1)
{
std::cout << "Input record [" << c << "] ? (y/n) ";
std::cin >> a;
if (a[0]=='y' || a[0]=='Y')
{
rec.setData();
fout.write((char*)&rec, sizeof(rec));
++c;
}
else break;
}
fout.close();
// output
Records* results = new Records[20];
Records rec1;
ifstream fin;
fin.open("file.txt", std::ifstream::binary);
while(!fin.eof())
{
fin.read((char*)&rec1, sizeof(rec1));
results[i] = rec1;
i++;
}
fin.close();
// eidt to print all records
for (int j=0; j<(i-1); j++)
{ std::cout << "record # = " << j << std::endl;
std::cout << " name = " << results[j].name;
std::cout << " roll = " << results[j].roll << std::endl;
}
return 0;
}
A test run
$ ./a.exe
Input record [0] ? (y/n) y
Enter name:
aaaa
Enter roll
1234
Input record [1] ? (y/n) y
Enter name:
bbbb
Enter roll
2345
Input record [2] ? (y/n) y
Enter name:
cccc
Enter roll
3456
Input record [3] ? (y/n) n
1234
I have a small project for a C++ course and I'm stuck trying to check if a value of a data member of STUDENT's class exists in the file(the "ID"). I've tried to use some function that I found on the internet to transform the integer value I'm searching for into a string and then use the find function, to search for it in each line of the file.
It works, but whenever I check one line from the file, it gets false pozitive, because the ID value(for example "12") is for example, identical to the value of age(also "12"). It does that because the age value comes before the ID value in my file and also in the string variable (and I can't change it). I don't know to search in the string for the value of ID only. I use the function "inputInfo" to input student1's member values from the keyboard, and function "checkID" to check if value of "ID" already exists in the file. Also, for another aspect of the project, I am seeking a way to search for occurrence of the ID and name data members values in the same file(once they are already written). One solution I've thought is to somehow start the search after the occurence of another character(for example the space character, given the fact that in the file, each field is delimited from another with a space), but I'm not sure the find function is able to do that.Thank you in advance for your help.Below is a part of the project's code in C++:
#include<iostream>
#include<string>
#include<fstream>
#include <sstream>
using namespace std;
int checkID(int idNumber)
{
string findID;
stringstream id_string;
id_string << idNumber;
findID = id_string.str();
int offset;
ifstream in;
in.open("Students.txt");
if(in.is_open())
{
string line;
while(getline(in, line))
{
if(offset = line.find(findID, 0)!= string::npos)
{
cout<<"The ID already exists. Insert a different ID!"<<endl;
return 0;
}
}
}
else
cout<<"File doesn't exist!"<<endl;
in.close();
}
class PERSON
{
protected:
string name;
string surname;
unsigned int age;
public:
void inputinfo()
{
cin>>name;
cin>>surname;
cin>>age;
}
outputinfo()
{
cout<<name<<endl;
cout<<surname<<endl;
cout<<age<<endl;
}
};
class STUDENT: public PERSON
{
int ID;
float marks_sum;
string belonging_class;
public:
inputInfo()
{
cout<<"Name:";
cin>>name;
cout<<"Surname:";
cin>>surname;
cout<<"Age:";
cin>>age;
do
{
cout<<"ID:";
cin>>ID;
}
while (checkID(ID)==0);
cout<<"Sum of marks:";
cin>>marks_sum;
cout<<"The belonging class:";
cin>>belonging_class;
}
void outputInfo()
{
cout<<name<<endl;
cout<<surname<<endl;
cout<<age<<endl;
cout<<ID<<endl;
cout<<marks_sum<<endl;
cout<<belonging_class<<endl;
}
friend std::ostream& operator << (std::ostream& os, const STUDENT& value )
{
os << value.name<<" "<<value.surname<<" "<<value.age<<" "<<value.ID<<" "<<value.marks_sum<<" "<<value.belonging_class<<std::endl;
return os;
}
};
STUDENT student1;
int writeInFile(STUDENT studentx)
{
ofstream os("Students.txt", ofstream::app);
os << studentx;
os.close();
}
int main()
{
int opt1, opt2;
char option;
do
{
cout<<"1 - Input data into file"<<endl<<"2 - Close program"<<endl;
cin>>opt1;
switch(opt1)
{
case 1:
do
{
cout<<endl;
cout<<"Choose one of variants"<<endl<<"1.Students"<<endl<<"2.Get back to main menu"<<endl;
cin>>opt2;
switch(opt2)
{
case 1:
do
{
cout<<"Do you wish to introduce a new student(Y/N)?";
cin>>option;
if(option!='N')
{
student1.inputInfo();
writeInFile(student1);
}
}
while (option!='N');
break;
}
}
while(opt2!=2);
break;
}
}
while(opt1!=2);
}
#include <sstream>
using namespace std;
bool isUniqueID(ifstream& file, int id)
{
string id_string = to_string(id);
string currently_read_line;
// The position of the searched key. So, in this case,
// only the 3rd value will be tested (starting from 0).
// John Doe 23 456
// | | | |
// 0 1 2 3 (the id)
int offset = 3;
while (getline(file, currently_read_line))
{
istringstream ss(currently_read_line);
string current_entry;
int counter = 0;
while (ss >> current_entry) {
if (current_entry == id_string && counter == offset) {
cout << "The Id already exists." << endl;
return false;
}
counter++;
}
}
// No match found
cout << "The ID does not exist yet." << endl;
return true;
}
Please note:
Just pass your opened file to the function. The file is opened once, instead of opening it every time you want to check an ID.
This requires to compile in -std=c++11 (for the to_string conversion)
[Update]
The offset variable tells the function what value to test for. A more consistent way to do this, would be to format the data as to have a key/value for each student entry. It works as it though.
I am learning OOP in C++ so I tried to practice a little. I want to create a "database" (using objects) of class and its students. I created a class for a student. Each have a name and age.
class Ziak {
public:
Ziak(int,string);
int getAge() {
return age;
}
string getName() {
return name;
}
private:
int age;
string name;
};
Ziak::Ziak(int age,string name) {
this->age=age;
this->name=name;
}
And I created a class of a Classroom , each is represented by its name , teacher and students ( vector of objects )
class Trieda {
public:
Trieda(string,string);
void fillStudents() {
while(1) {
int age;
string name;
cout << "Name: ";
getline(cin,name);
cout << "Age: ";
cin >> age;
Ziak newStudent(age,name);
n.push_back(newStudent);
if(cin.eof()) {
break;
}
}
}
string getTeacher() {
return ucitel;
}
string getNamesOfStudents() {
for(unsigned i = 0; i < n.size(); i++) {
cout << "hey " << n[i].getName() << endl;
}
}
protected:
vector<Ziak> n;
string nazov;
string ucitel;
};
Trieda::Trieda(string nazov,string ucitel) {
this->nazov = nazov;
this->ucitel = ucitel;
}
and I am just calling its methods in main:
int main() {
Trieda newClass("4A","Ms Foster");
newClass.fillStudents();
newClass.getNamesOfStudents();
return 0;
}
My problem here is the method fillStudents() output starts pretty nice:
Name: // insert name
Age : // insert age
but the second iteration looks worse:
Name:Age: // insert something
and the third iteration is an infinite loop printing Name:Age: till the end of the world.
I tried to just use cin >> name instead of getline, e.g:
void fillStudents() {
while(1) {
int age;
string name;
cout << "Name: ";
cin >> name;
/*getline(cin,name);*/
cout << "Age: ";
cin >> age;
if(cin.eof()) {
break;
} else {
Ziak newStudent(age,name);
n.push_back(newStudent);
}
cin.clear();
}
}
It works. But it works like this:
Name: // insert name
Age : // insert age
// it works till the last one when i press ctrl+Z as eof (currently on windows)
// it outputs Age: Hey + first name ....
Hey name 2 // and so on , then it crashes
What causes this? I suspect it could be something with buffer not being cleared but I tried cin.clear() and it happened too. How can I implement it with getline (I wanted full name as name input e.g John Wicked).
I am trying to figure it out but I'm just a beginner with C++ so my knowledge is limited.
Edit
I fixed it using cin.get() as advised from question posted in comments, now my function looks like this:
void fillStudents() {
while(1) {
int age;
string name;
cout << "Name: ";
//cin >> name;
getline(cin,name);
cout << "Age: ";
cin >> age;
if(cin.eof()) {
break;
} else {
if(cin.fail()) {
cout<< "chyba ";
break;
}
Ziak newStudent(age,name);
n.push_back(newStudent);
}
cin.get();
}
}
What still makes me uncomfortable is the output with cout. It produces this:
Name: John
Age: 15
Name: Lia
Age: 25
Name: Age: hey John
hey Lia
The Name: Age: still gets printed after eof, I tried to put cin.eof() test at the start of the while loop but it messed up all of the output. How can I modify the code without it showing the cout after eof?
You need to check for eof (Ctrl+z(^Z)) after name has been entered and after age has been entered. If you enter Ctrl+z for name then the eofbit flag will be set on cin but not caught until after outputting Age:. The reason it doesn't pause for age input is because:
The extraction also stops if the end of file is reached in [the istream] or if some other error occurs during the input operation. - C++ Reference - getline
Note: The istream in the quote above is cin in your code.
Your code should resemble:
// above code removed for brevity
cout << "Name: ";
getline(cin,name);
if(cin.eof()) {
break;
}
cout << "Age: ";
cin >> age;
if(cin.eof()) {
break;
} else {
// below code removed for brevity
Output:
Tested on Windows with CodeBlocks and GCC.
Name: ^Z[Enter]
Process returned 0 (0x0) execution time : 1.685 s
Press any key to continue.
Name: John
Age: ^Z [Enter]
Process returned 0 (0x0) execution time : 1.685 s
Press any key to continue.
So far I am able to open a txt file and store them as variables.
My txt file looks like this
Tim, 24, Male
I have been able to store them as variables such as name, age, gender
This is my code
ifstream inputfiles ("test.txt");
if(!inputfiles.is_open())
{
}
else
{
while(inputfiles >> name >> age >> gender)
{
cout << name << "\n";
cout << age << "\n";
cout << gender << "\n";
}
However, my code doesn't store the values as variables when my txt file looks like this...
Tim
24
Male
How do I modify my code such that it can read my file line by line and store it in its variables?
If I am right, You want to store it like:
Tim 24 Male
John 25 Male
Use a class
class data
{
public:
char name[10],gen;
int age;
void getdata()
{
cout<<"Enter Name";
gets(name);
cout<<Enter age";
cin>>age;
cout<<"enter gender";
cin>>gen;
}
void putdata()//use cout statements here
{
//put cout statements
}
};
Now in your main function,use write functon
fstream f;
f.open("YourFile.txt",ios::in|ios::out);
data r;
for(i=0;i<10;i++)
{
r.getdata();
f.write((char*)&r,sizeof(r));
}
Remember,always use read function to print the database values if you used write.
f.seekg(0,ios::beg);
while(!f.eof())
{
f.read((char*)&r,sizeof(r));
}
If you want to store the text as it is without conversion...use put function.