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

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.

Related

What could be a better solution to calling a function recursively?

This is a simple function which will take value from user and if value is invalid then the function will call itself recursively until a valid input is provided.
#include<iostream>
using namespace std;
void getnum(){
int num;
string strnum;
getline(cin, strnum);
try{
num = stoi(strnum);
}
catch(invalid_argument &ia){
cout<<"Invalid argument\n";
getnum();
}
cout<<"\n"<<num;
}
int main(){
getnum();
return 0;
}
/*output(input: abc,abc,abc,4):
4
2494464
2494464
4201200
*/
Using the recursive approach the program is creating a new instance of the function every time an invalid argument is passed. After receiving a valid argument, function is printing multiple values(garbage values) of num due to multiple instances created.
The problem is that I want only the last value(correct one) to be printed. So I tried setting a 'flag' to control the execution of cout<<"\n"<<num.
#include<iostream>
using namespace std;
void getnum(){
int flag = 0;
int num;
string strnum;
getline(cin, strnum);
try{
flag = 1;
num = stoi(strnum);
}
catch(invalid_argument &ia){
flag = 0;
cout<<"Invalid argument\n";
getnum();
}
if(flag)
cout<<"\n"<<num;
}
int main(){
getnum();
return 0;
}
/*output(input:abc,abc,abc,4)
4 */
It solves my problem but still multiple instances are being created which I think is wastage of memory.
Is there any better way to do this without using a lot of memory(recursion)?
You get multiple outputs because you print outside "the happy path" - move printing inside the try block.
It's even clearer to put the entire "happy path" inside the try:
void getnum(){
try {
string strnum;
getline(cin, strnum);
int num = stoi(strnum);
cout<<"\n"<<num;
}
catch(invalid_argument &ia){
cout<<"Invalid argument\n";
getnum();
}
}
The idiomatic solution is to loop rather than recurse:
void getnum(){
while (true)
{
try {
string strnum;
getline(cin, strnum);
int num = stoi(strnum);
cout << "\n" << num;
return;
}
catch (invalid_argument &){
cout<<"Invalid argument\n";
}
}
}

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

c++ prevent to input not integer

In my code, I want to prevent the user input not integer words. my code is bottom.
#include<iostream>
#include<fstream>
#include<string>
#include<boost/regex.hpp>
#include<iomanip>
using namespace boost;
using namespace std;
int main()
{
int number;
string name,Telephone,email;
ofstream myoutfile("directory.txt");
ifstream myinfile;
bool isvalid=false;
char a[256];
char b[256];
regex reg_email("^\\w+([\\.-]?\\w+)*#\\w+([\\.-]?\\w+)*(\\.\\w{2,3})+$");
regex reg_tel("^\\(?(\\d{3})\\)?-?(\\d{3})-(\\d{4})$");
while(number!=3)
{
cout<<"(1)Add a new record"<<endl;
cout<<"(2)Display the entire database"<<endl;
cout<<"(3)Exit"<<endl;
cin>>number;
if(number==1)
{
cout<<"enter your name."<<endl;
cin>>name;
cout<<"enter your email."<<endl;
cin.ignore(INT_MAX,'\n');
cin.getline(b,256);
while (regex_match(b,reg_email)==0)
{
cout<<"data wrong!!!!!!"<<endl;
cin.getline(b,256);
}
cout<<"enter your telephone numbers. EX:012-111-1111"<<endl;
cin.ignore(INT_MAX,'\n');
cin.getline(a,256);
while(regex_match(a,reg_tel)==0)
{
cout<<"data wrong!";
cin.getline(a,256);
}
myoutfile<<setiosflags(ios::left)<<setw(30)<<name<<setiosflags(ios::left)
<<setw(30)<<b<<setiosflags(ios::left)<<setw(30)<<a<<endl;
}
else if(number==2)
{
myinfile.open("directory.txt",ios::in);
string temp;
cout<<setiosflags(ios::left)<<setw(30)<<"name";
cout<<setiosflags(ios::left)<<setw(30)<<"email";
cout<<setiosflags(ios::left)<<setw(30)<<"telephone"<<endl;
while(!myinfile.eof())
{
getline(myinfile, temp);
cout<<temp<<endl;
}
myinfile.close();
}
else if(number==3)
{
cout<<"BYE!";
}
else if(scanf("%d",&number)!=1)
{
cout<<"Enter number!!!";
break;
}
}
return 0;
}
I have some question in the code.
First,
It will be fine when while loop run the first time,
but when the loop run the second time, I input an non-integer, it will show messy code.
Does anyone know?
Second,
cout<<"enter your telephone numbers. EX:012-111-1111"<<endl;
cin.ignore(INT_MAX,'\n');
cin.getline(a,256);
while(regex_match(a,reg_tel)==0)
{
cout<<"data wrong!";
cin.getline(a,256);
}
in above code, even if I type the correct format of the telephone number,
it always show me the "data wrong!" message, but I type it again, the regex_match test will be fine.
above is my question, sincerely thanks!

c++ file handling - class objects

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