c++ file handling - class objects - c++

The following code read 3 obj and write them into a file.
however im unable to retrieve objects properly using the below code.
data is duplicated and is not in order
plz help
old code :
#include<fstream.h>
#include<conio.h>
class mail
{
public:
char un[25]; // user name
char pd[25]; // passsword
void reg(int);
} obj[5];
void mail::reg(int k)
{
int i;
i=k;
clrscr();
cout<<"Enter user name ( enter unique name )\n";
cin>>un;
cout<<"Enter password\n";
cin>>pd;
ofstream filout;
filout.open("email",ios::app||ios::binary);
if(!filout)
{
cout<<"cannot open file\n";
}
else
{
cout<<"\n "<<i;
filout.write((char *)&obj[i],sizeof(mail));
filout.close();
}
cout<<"You are now registered. \n";
getch();
} // end of sign up or register func
void main()
{
int t;
clrscr();
obj[0].reg(0);
obj[1].reg(1);
obj[2].reg(2);
mail obj2;
ifstream filein;
filein.open("email",ios::in||ios::binary);
if(!filein)
{
cout<<"Unable to open file to read\n";
}
else
{
while(!filein.eof())
{
filein.read((char *)&obj2,sizeof(obj2));
cout<<"username "<<obj2.un<<" passwword "<<obj2.pd<<"\n";
}
filein.close();
}
getch();
}
Also please tell me how to put code into stackoverflow. Manually putting 4 spaces after copy pasting is very tiresome
new code after making changes :
#include<fstream.h>
#include<conio.h>
struct mail
{
char un[25]; // user name
char pd[25]; // passsword
void reg(int);
} obj[5];
void mail::reg(int k)
{
int i=k;
clrscr();
cout<<"Enter user name ( enter unique name )\n";
cin>>un;
cout<<"Enter password\n";
cin>>pd;
ofstream filout;
filout.open("email",ios::app|ios::binary);
if(!filout) {
cout<<"cannot open file\n";
} else {
cout<<"\n "<<i;
filout.write((char *)&obj[i],sizeof(mail));
filout.close();
}
cout<<"You are now registered. \n";
getch();
} // end of sign up or register func
int main()
{
int t;
clrscr();
obj[0].reg(0);
obj[1].reg(1);
obj[2].reg(2);
mail obj2;
ifstream filein;
filein.open("email",ios::in|ios::binary);
if(!filein) {
cout<<"Unable to open file to read\n";
} else {
while(filein) {
filein.read((char *)&obj2,sizeof(obj2));
cout<<"username "<<obj2.un<<" passwword "<<obj2.pd<<"\n";
}
filein.close();
}
getch();
}
Im still facing problem. I write 3 object. But iam getting 4 output records. Last one is duplicated.

You have an improper file loop, an EOF() loop is bad practice and often can lead to undefined behavior, a proper loop would be as follows:
filein.read((char *)&obj2,sizeof(obj2));
while(filein)
{
cout<<"username "<<obj2.un<<" passwword "<<obj2.pd<<"\n";
filein.read((char *)&obj2,sizeof(obj2));
}
the structure of this loop allows the file to check the file for EOF before reading again, while the eof loop will read the eof in THEN check, leading to some junk at the end.
your fileIn variable uses improper flags, you use '||' the logical OR
operator instead of the '|' logical bitwise operator. This could be a
possible reason for your error.
you have some issues with your program, void main() make most
people here cringe, main ALWAYS returns int

Related

Problem with read and write functions in c++ [duplicate]

First time execution is success without any error but when it creates Data.bin I get some error when I use fread.
Sorry I don't know how to ask it so please look at the program.
I commented the error making statement.
#include<iostream>
#include<vector>
using namespace std;
typedef struct myStuff
{
int cdno;
string content,des;
}MS;
int main()
{
vector<MS> data;
int i=0;
string in;
FILE *fr=NULL,*fw=NULL;
fr=fopen("Data.bin","rb");
//----------------------------------------------------------------------
if(fr!=NULL)
{
do
{
data.resize(++i);
}while( fread(&data[i-1],sizeof(MS),1,fr) ); //ERROR
fclose(fr);
}
else
data.resize(++i);
//----------------------------------------------------------------------
while(1)
{
cout<<"Enter x to exit or c to continue updating data: ";
cin>>in;
if(in=="x"||in=="X")
{
fw=fopen("Data.bin","wb");
fwrite(&data[i],sizeof(MS),i,fw);
fclose(fw);
exit(0);
}
else if(in=="c"||in=="C")
{
cout<<"Enter CD no: ";
cin>>data[i-1].cdno;
cout<<"Enter Contents: ";
cin>>data[i-1].content;
cout<<"Enter Description: ";
cin>>data[i-1].des;
data.resize(++i);
}
else
cout<<"Try Again..."<<endl;
}
}
you shouldn't use sizeof(string) or sizeof a structure that contains a string, that's meaningless, it just gives you the compile time (static) size of the class string. you should instead use string.size() which returns the dynamic size of the string.

Segmentation fault in Data file handling in c++ [duplicate]

This question already has answers here:
Why does C++ reject appending a structure to a binary file if it contains a member of the string class?
(2 answers)
Closed 5 years ago.
I've written a small code in c++ to understand data file handling. The program consists of accepting entries, writing them to a .dat file and searching for a particular entry. So far, only the writing function is working, the reading and the searching function give a segmentation fault error. What's going wrong?
#include<iostream>
#include<string>
#include<fstream>
#include<stdlib.h>
using namespace std;
class data_base
{
string name;
long int no;
public:
void input()
{
cout<<"\nEnter name:";
cin>>name;
cout<<"Enter ph number:";
cin>>no;
}
void display()
{
cout<<name<<"\t"<<no;
}
string retname()
{
return name;
}
long int retno()
{
return no;
}
};
void display_all()
{
data_base d;
fstream in;
in.open("database.dat",ios::in|ios::binary);
if(!in.is_open())
cout<<"Error opening file";
else{
while(in.read((char *)&d,sizeof(d)))
{
d.display();
}
}
in.close();
}
void search_name()
{
data_base d;
fstream in;
string s;
in.open("database.dat",ios::in|ios::binary);
if(!in.is_open())
cout<<"Error opening file";
else{
cout<<"\nEnter name to be searched:";
cin>>s;
while (in.read((char *) &d,sizeof(d))) {
if(s==d.retname())
{
d.display();
}
}
}
in.close();
}
void search_no()
{
data_base d;
fstream in;
long int l;
in.open("database.dat",ios::in|ios::binary);
if(!in.is_open())
cout<<"Error opening file";
else{
cout<<"\nEnter number to be searched:";
cin>>l;
while (in.read((char *) &d,sizeof(d)))
{
if(l==d.retno())
{
d.display();
}
}
}
in.close();
}
int main()
{
int ch;
fstream file;
data_base d,e;
string s;
while(1)
{
cout<<"1.Add entry\n2.Search by name\n3.Search by
number\n4.Display all entries\5.Exit"<<endl;
cin>>ch;
switch (ch) {
case 1: d.input();
file.open("database.dat",ios::out|ios::app|ios::binary);
if(!file.is_open())
cout<<"Error opening file";
else
{
file.write((char *)&d,sizeof(d));
cout<<"Entry added!"<<endl;
}
file.close();
break;
case 2:search_name();
break;
case 3:search_no();
break;
case 4:display_all();
break;
case 5: exit(0);
}
}
}
class data_base
{
string name;
...
}
...
data_base d;
...
file.write((char *)&d,sizeof(d));
You are already doomed here. The std::string struct has a pointer inside. Reinterpreting this pointer as a char array gives you some sequence of chars. You save it to a file and then read it some time later.
At that moment your newly read data_base variable has exact binary representation as the one before. But now the internal pointer of std::string no longer points to a valid memory address, hence segfault.
Note that segfaulting is actually good. In some bad case the memory address would be valid but it would point to some completely unrelated (random) data. That would be a bug extremely hard to find.
You are doing this wrong from the begining. Don't cast to/from char* for serialization/deserialization of data. Use proper serialization techniques, e.g. convert the structure to xml, json, google protobuf or even come up with something custom. Just don't reinterpret raw memory. Even if there are no pointers inside your struct the binary representation is compiler, os and cpu dependent.

C++ encrypt and decrypt secret messages using files

I have my prototypes in a header file, but I need some help. I am having some trouble getting the program to compile all the way through. It appears to be getting caught in a loop with the input. Possibly some issues with the functions. Thanks in advance for any input.
#include <iostream>
#include <conio.h>
#include "header.h"
#include <fstream>
class Caesar
{
public: void readText(char *input);
void encrypt(char *input,char *output,char *key);
void decrypt(char *input,char *output,char *key);
};
void main()
{
Caesar a;
char key[1000];
ifstream fin;
int choice;
char input[100],output[100];
cout<<"\n Enter input file: ";
cin>>input;
cout << input;
cout<<"\n Enter output file: ";
cin>>output;
cout <<output;
cout<<"\n Enter key: ";
cin>>key;
cout <<key;
cout<<"\n\n 1. Encrypt\n 2. Decrypt\n\n Select choice(1 or 2): "<< endl;
cin >> choice;
cout << choice;
a.readText(input);
if(choice==1)
{
a.encrypt(input,output,key);
}
if(choice==2)
{
a.decrypt(input,output,key);
}
else
{
cout<<"\n\n Unknown choice";
}
}
void Caesar::readText(char *input)
{
ifstream reader;
char buf;
reader.open(input);
cout<<"\n\n <--- "<<input<<" --->\n";
buf=reader.get();
while(!reader.eof())
{
cout<<buf;
buf=reader.get();
}
reader.close();
}
void Caesar::encrypt(char *input,char *output,char *key)
{
ifstream reader;
ofstream writer;
char buf;
reader.open(input);
writer.open(output);
buf=reader.get();
while(!reader.eof())
{
if(buf>='a'&&buf<='z')
{
buf-='a';
buf+=key[buf];
buf%=26;
buf+='A';
}
writer.put(buf);
buf=reader.get();
}
reader.close();
writer.close();
readText(input);
readText(output);
}
void Caesar::decrypt(char *input,char *output,char *key)
{
ifstream reader;
ofstream writer;
char buf;
reader.open(input);
writer.open(output);
buf=reader.get();
while(!reader.eof())
{
if(buf>='A'&&buf<='Z')
{
buf-='A';
buf+=26-key[buf];
buf%=26;
buf+='a';
}
writer.put(buf);
buf=reader.get();
}
reader.close();
writer.close();
readText(input);
readText(output);
}
if(choice=1)
should be
if(choice==1)
and also in the other if
In your case, you are assigning the value 1 to choice, then test if choice is true, and it is, since any non-zero numeral type is implicitly casted to bool true.
I have just executed your code and tried debugging it and took a screen shot
you program gets into a loop after entering the choice.there is no problem with cin>>.
From your comments, it seems like you're just trying to debug main. Everything seems to work fine. What are you inputting for key? If it's a very large integer, that may be your problem as it might exceed the maximum integer range and cause overflow.
Your key is an integer variable. You are inputting a string for the file name that holds your key, so that should be changed to a C string array. Change all of the passed key parameters to char* instead of int.
You have an infinite loop when the readText() function is called.
Maybe try this:
void Caesar::readText(char *input)
{
ifstream reader(input);
if(reader.is_open())
{
char buf;
cout<<"\n\n <--- "<<input<<" --->\n";
while(reader.get(buf))
{
cout << buf;
}
}
reader.close();
}
Make sure that your text file is in the same folder as your code. See this for more details: ifstream not opening file

error in file handling in c++--no matching function for call to `std::basic_fstream<char, std::char_traits<char> >::open(const char[8], bool)'

I was trying out a file handling program to enter a record and in another program try to delete a record. I seem to be getting this error-
no matching function for call to `std::basic_fstream >::open(const char[8], bool)'
for every f.open statement which has an ios::binary declaration in it.
here are the codes
this one if for entering records
#include<iostream.h>
#include<fstream.h>
class employee
{
int code;
char name[20];
char desig[15];
float salary;
public: void get_emp();
};
void employee:: get_emp()
{
cout<<"Code--> ";
fflush(stdin);
cin>>code;
cout<<"Name--> ";
fflush(stdin);
gets(name);
cout<<"Designation--> ";
fflush(stdin);
gets(desig);
cout<<"Salary--> ";
fflush(stdin);
cin>>salary;
}
int main()
{
fstream f;
char ch;
f.open("EMP.dat", ios::binary||ios::app);
employee emp;
cout<<"Enter data:\n";
do
{
emp.get_emp();
f.write((char*)&emp,sizeof(emp));
cout<<"Entre more???(y/n)";
cin>>ch;
}while((ch=='y')||(ch=='Y'));
f.close();
system("pause>null");
return 0;
}
this is for deleting record
#include<iostream.h>
#include<fstream.h>
#include<stdlib.h>
struct employee
{
int code;
char name[20];
char desig[15];
float salary;
}emp;
int main()
{
int xcode; //temporary declaration for employee code
int flag = 0;
fstream ef, tf;
//ef opened for reading, tf opened for transferring all records including modified record
ef.open("EMP.dat", ios::binary|| ios::in);
tf.open("TEMP.dat", ios::binary|| ios::out);
cout<<"Enter employee code to delete:";
cin>>xcode;
while(ef)
{
if(!ef)
exit(0);
ef.read((char*)&emp, sizeof(emp));
if(emp.code == xcode)
{
flag = 1;
}
else
tf.write((char*)&emp, sizeof(emp));
}
ef.close();
tf.close();
if(flag == 1)
cout<<"Record deleted.";
else
cout<<"Not found.";
fstream xf, yf;
//tf opened for reading
xf.open("TEMP.dat", ios::binary||ios::in);
//ef opened for copying all records from TEMP.dat
yf.open("EMP.dat",ios::binary||ios::out);
while(xf)
{
if(!xf)
exit(0);
xf.read((char*)&emp, sizeof(emp));
yf.write((char*)&emp, sizeof(emp));
}
xf.close();
yf.close();
system("pause");
return 0;
}
please help. I need it for my exams.
Thank you
Bitwise OR is a single pipe (|), not a double pipe.

Program hangs because of some reason

The following code is supposed to read records from input and store them in a file called file.dat. Then it is supposed to arrange these records in ascending order, but for some reason the program hangs in the second while loop at line "file1.seekg(-(sizeof(r)),std::ios::cur);". Can someone please tell me what's wrong?
#include <iostream>
#include <fstream>
#include <strstream>
int main()
{
std::ofstream file;
file.open("file.dat",std::ios::trunc|std::ios::binary);
if(!file)
std::cout<<"unable to open for output";
struct record
{
char code[6];
char name[20];
int i;
};
record r;
int a = 0;
while(1)
{
std::cout<<"Record " << a + 1 << std::endl;
std::cout<<"Enter character code, name and an int \n";
std::cin.ignore();
std::cin.getline(r.code,6);
std::cin.getline(r.name,20);
std::cin>>r.i;
file.write((char *)&r,sizeof(r));
std::cout<<"\nAdd another (y\\n) : ";
char c;
std::cin>>c;
if(c == 'n')
break;
a++;
std::cout<<'\n'<<'\n';
}
file.close();
std::fstream file1("file.dat",std::ios::in|std::ios::out|std::ios::binary);
if(!file1)
std::cout<<"unable to open file1";
else
{
if(a>0)
{ while(a)
{
file1.seekp(0);
for(int i = a; i>0;i--)
{
record r1;
file1.read((char *)&r,sizeof(r));
file1.read((char *)&r1,sizeof(r1));
if(r1.i < r.i)
{
file1.seekp(-(sizeof(r)*2),std::ios::cur);
file1.write((char *)&r1,sizeof(r));
file1.write((char *)&r,sizeof(r));
file1.seekg(-(sizeof(r)),std::ios::cur);
}
}
a--;
}
}
file1.close();
}
std::ifstream file2("file.dat",std::ios::binary);
if(!file2)
std::cout<<"unable to open file2";
else
while(1)
{
std::cout<<"\n\n";
file2.read((char *)&r,sizeof(r));
if(file2.eof())
break;
std::cout<<r.code<<'\t'<<r.name<<'\t'<<r.i;
}
}
first
change std::get.ignore -> std::cin.ignore()
if you want to discard one character.
it compiled well and created file.dat file..
you might check the record inside file.dat though
If you are trying to ignore the new line character entered after the actual dat, then you have to use:
std::cin.ignore();
If you want more reference on use of ignore go to this LINK