I am trying to write a program where you register a bank account and modify it. This is the code (Not full but just trying to experiment with file handling; I am a beginner at programming)
#include <iostream>
#include <fstream>
#include <string>
std::ofstream outfile;
std::ifstream infile;
std::fstream inout;
struct bank{
int acc_nr;
std::string emri;
std::string mbiemri;
};
std::istream& operator>> (std::ifstream& in, bank& klient)
{
in >> klient.emri;
in >> klient.mbiemri;
in >> klient.acc_nr;
return in;
}
std::ostream& operator<< (std::ofstream& out, bank& klient)
{
out << klient.emri << std::endl;;
out << klient.mbiemri << std::endl;
out << klient.acc_nr << std::endl;
return out;
}
std::ostream& operator<< (std::fstream& out, bank& klient)
{
out << klient.emri << std::endl;;
out << klient.mbiemri << std::endl;
out << klient.acc_nr<< std::endl;
return out;
}
std::istream& operator>> (std::fstream& in, bank& klient)
{
in >> klient.emri;
in >> klient.mbiemri;
in >> klient.acc_nr;
return in;
}
std::istream &read(bank &klient, std::istream &is)
{
std::cout << "Jepni emrin: ";
is >> klient.emri;
std::cout << "Jepni mbiemrin: ";
is >> klient.mbiemri;
std::cout << "Jep numrin e akaundit: ";
is >> klient.acc_nr;
return is;
}
const std::ostream &print(bank klient, std::ostream &os)
{
std::cout << "Emri: ";
os << klient.emri;
std::cout << "\nMbiemri: ";
os << klient.mbiemri;
std::cout << "\nNumri i akaundit: ";
os << klient.acc_nr;
return os;
}
void read_infile(bank &klient)
{
read(klient, std::cin);
outfile.open("C:\\publik\\sample.dat", std::ios::app| std::ios::binary);
outfile.write(reinterpret_cast <char *>(&klient), sizeof(bank));
outfile.close();
}
void print_outfile(bank klient)
{
infile.open("C:\\publik\\sample.dat", std::ios::in| std::ios::binary);
infile.read(reinterpret_cast <char *>(&klient), sizeof(bank));
infile.close();
}
void kerko(std::string emri, std::streampos& a)
{
bank temp;
inout.open("C:\\publik\\sample.dat", std::ios::in | std::ios::out | std::ios::binary);
while (inout.read(reinterpret_cast <char *>(&temp), sizeof(bank)))
{
if (emri == temp.emri) // emri = name.
{
print(temp, std::cout);
a = inout.tellg();
inout.close();
break;
}
}
}
int main()
{
bank klient;
bank temp2;
std::string emri;
std::streampos a;
std::cin >> emri;
bank temp;
kerko(emri,a);
std::cout <<std::endl;
system("pause");
return 0;
}
The code reads a name, searches through the file and then displays its information. The searching and displaying are successful but I get this error
Unhandled exception at 0x77CFDF58 (msvcp120d.dll) in Banke.exe:
0xC0000005: Access violation reading location 0x00DCAB9C.
The code does not execute past the print function call in the while loop.
Thank you for your time.
There are several things that are wrong here.
First of all you cannot do this:
read(klient, std::cin);
outfile.open("C:\\publik\\sample.dat", std::ios::app| std::ios::binary);
outfile.write(reinterpret_cast <char *>(&klient), sizeof(bank));
your &klient is a complex structure, using a type (std::string) of which you know nothing about its internal layout. It may have pointers pointing 'outside' of it. To read a record you should so something like this;
bank klient ;
std::ifstream istream("name", std::ios::app| std::ios::binary); // or use open
istream >> klient ;
And here we get to second point. This definition is quite ok (I would have used std::ostream instead of std::ofstream but that's a minor point)
std::ostream& operator<< (std::ofstream& out, bank& klient)
{
out << klient.emri << std::endl;;
out << klient.mbiemri << std::endl;
out << klient.acc_nr << std::endl;
return out;
}
The main point is that when you want to read emri or mbiemri how do you know where the first ends, and the second starts? The simplest way could be insert a space. It works only if emri/mbiemri do not contain spaces themselves, but for a beginner could be a good starting point.
And that's all for now, you have enough to think about...
Related
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!
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';
}
}
}
This question has been asked before but the other question/answers used concepts I'm not yet familiar with in C++.
I need to read data from a file into a vector of structs.
I have the following code but I'm confused about what to put in (....), that is if I have the correct logic.
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
struct Parts{
std::string partNum;
char partClass;
int stock;
float cost;
};
bool readFile(std::vector <Parts>&);
int displayMenu();
int main(){
std::vector <Parts> pVector;
readFile(pVector);
if (!readFile(pVector)){
std::cout << "Error reading file!" << std::endl;
}
else{
displayMenu();
}
return 0;
}
bool readFile(std::vector <Parts> &pVector){
std::ifstream inputFile("parts.txt");
if (inputFile.fail()){
std::cout << "Error reading file!" << std::endl;
return false;
}
else{
while (....){
pVector.emplace_back(....);
}
return true;
}
}
Sample lines from the file:
P-42936 A 18 129.79
P-43179 A 47 35.60
P-43264 B 31 103.81
P-43367 B 5 32.39
P-43378 A 46 6.38
P-43622 A 10 155.36
You want that :
bool readFile(std::vector <Parts> &pVector){
std::ifstream inputFile("parts.txt");
if (inputFile.fail()){
std::cout << "Error reading file!" << std::endl;
return false;
}
else {
Parts part;
while (inputFile >> part.partNum >> part.partClass >> part.stock >> part.cost)
pVector.emplace_back(part);
return true;
}
}
In main you call two time the read function :
readFile(pVector);
if (!readFile(pVector)){
very probably the first call must be removed
It can be also interesting to define the operator >> for Parts rather than to have the code doing that in readFile
So :
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
struct Parts{
std::string partNum;
char partClass;
int stock;
float cost;
};
std::istream & operator >>(std::istream & is, Parts & part) {
if (is >> part.partNum >> part.partClass >> part.stock)
is >> part.cost;
return is;
}
bool readFile(std::vector <Parts>&);
//int displayMenu();
int main(){
std::vector <Parts> pVector;
if (!readFile(pVector)){
std::cout << "Error reading file!" << std::endl;
}
else{
//displayMenu();
// to check, of course operator << can be defined too
for (auto p : pVector)
std::cout << p.partNum << '/' << p.partClass << '/' << p.stock << '/' << p.cost << std::endl;
}
return 0;
}
bool readFile(std::vector <Parts> &pVector){
std::ifstream inputFile("parts.txt");
if (inputFile.fail()){
std::cout << "Error reading file!" << std::endl;
return false;
}
else {
Parts part;
while (inputFile >> part)
pVector.emplace_back(part);
return true;
}
}
Compilation and execution:
pi#raspberrypi:/tmp $ g++ -Wall r.cc
pi#raspberrypi:/tmp $ cat parts.txt
P-42936 A 18 129.79
P-43179 A 47 35.60
P-43264 B 31 103.81
P-43367 B 5 32.39
P-43378 A 46 6.38
P-43622 A 10 155.36
pi#raspberrypi:/tmp $ ./a.out
P-42936/A/18/129.79
P-43179/A/47/35.6
P-43264/B/31/103.81
P-43367/B/5/32.39
P-43378/A/46/6.38
P-43622/A/10/155.36
pi#raspberrypi:/tmp $
I suggest adding overloads for operator>> and operator<<:
#include <iostream>
#include <string>
#include <vector>
struct Part { // I renamed it because it only holds info about one part
std::string partNum;
char partClass;
int stock;
float cost;
};
std::istream& operator>>(std::istream& is, Part& p) {
return is >> p.partNum >> p.partClass >> p.stock >> p.cost;
}
std::ostream& operator<<(std::ostream& os, const Part& p) {
return os << p.partNum << ' ' << p.partClass << ' ' << p.stock << ' ' << p.cost;
}
This makes extracting or printing one Part easy:
bool readFile(std::vector<Part>& pVector){
std::ifstream inputFile("parts.txt");
if(inputFile) {
Part tmp;
while(inputFile >> tmp) // extract one Part at a time using operator>>
pVector.emplace_back(tmp);
return true;
} else {
std::cout << "Error reading file!" << std::endl;
return false;
}
}
I am reading a structure named "Highscore" from a binary file. I print the read data in the console and it looks fine. After that, I insert them into a vector with the push_back method and when I'm done, I return the vector.
After the return line, I get the following error (translated from French):
"Exception not handled at 0x00007FF6223FF017 in Project1.exe : 0xC0000005 : access violation while reading from 0xFFFFFFFFFFFFFFFF.".
Here is my code:
struct Highscore{
string username;
int points;
};
vector<Highscore> ReadFromHighscores(){
fstream highscoresFiles;
highscoresFiles.open("highscores.db", ios::in | ios::out | ios::binary | ios::app);
highscoresFiles.seekg(0);
Highscore output;
vector<Highscore> highscores;
highscoresFiles.read(reinterpret_cast<char *>(&output), sizeof(Highscore));
cout << "Read : " << output.points << output.username << endl;
Highscore temp;
temp.points = output.points;
temp.username = output.username;
if (!highscoresFiles.eof()) {
highscores.push_back(temp);
}
highscoresFiles.close();
return highscores;
}
As having been pointed out, std::string contains a char* (which you are saving and restoring) to the real data. The actual data is not saved and the pointer you restore is causing the crash. To fix that you can create operators for streaming to/from files and dump the username c-string (including the terminating \0) and then write the points int raw. This should work as long as your usernames don't contain \0 in the middle of the string (unusual but valid).
#include <iostream>
#include <iomanip>
#include <vector>
#include <fstream>
struct Highscore{
std::string username;
int points;
Highscore(const std::string& n, int p) : username(n), points(p) {}
Highscore() : Highscore("",0) {}
// operator to save a Highscore to file
friend std::ofstream& operator<<(std::ofstream&, const Highscore&);
// operator to read a Highscore from file
friend std::ifstream& operator>>(std::ifstream&, Highscore&);
// operator to print a Highscore on other ostreams (like std::cout)
friend std::ostream& operator<<(std::ostream&, const Highscore&);
};
std::ofstream& operator<<(std::ofstream& os, const Highscore& hs) {
os.write(hs.username.c_str(), hs.username.size()+1);
os.write(reinterpret_cast<const char*>(&hs.points), sizeof(hs.points));
return os;
}
std::ifstream& operator>>(std::ifstream& is, Highscore& hs) {
std::getline(is, hs.username, '\0');
is.read(reinterpret_cast<char*>(&hs.points), sizeof(hs.points));
return is;
}
std::ostream& operator<<(std::ostream& os, const Highscore& hs) {
os << std::setw(15) << std::left << hs.username << std::setw(8) << std::right << hs.points;
return os;
}
int main() {
// create "highscores.db"
{
std::vector<Highscore> highscores {
{"MadBrother33", 234234},
{"Barny", 14234},
{"Bart", 1434}
};
std::ofstream out("highscores.db", std::ios::binary);
for(auto& hs : highscores) {
out << hs;
}
}
// read "highscores.db"
{
std::vector<Highscore> highscores;
{
Highscore hs;
std::ifstream in("highscores.db", std::ios::binary);
while(in>>hs) {
highscores.emplace_back(std::move(hs));
}
}
for(auto& hs : highscores) {
std::cout << hs << "\n";
}
}
}
Output
MadBrother33 234234
Barny 14234
Bart 1434
I'm working on boost::asio::streambuf and found out that I can send/get a struct using it, but when I send a struct I just can't get it as I have sent it. The documentation says that one should use commit() and consume(), but where should I use them here?
struct person
{
int m_id;
std::string m_message;
};
std::istream& operator>>(std::istream& in, struct person& p)
{
return in >> p.m_id >> p.m_message;
}
std::ostream& operator<<(std::ostream& out, struct person& p)
{
return out << p.m_id << " " << p.m_message;
}
int main()
{
boost::asio::streambuf buf;
std::ostream out(&buf);
person p;
p.m_id = 1;
p.m_message = "Hello World!";
out << p;
std::istream in(&buf);
person p1;
in >> p1;
cout << "ID: " << p1.m_id << endl;
cout << "Message: " << p1.m_message << endl;
return 0;
}
The problem is with strings so when I type only "hello" (without world), it works fine, but if I add "world!" as shown above it just doesn't see the added "world!", why?
There are a number of issues.
Firstly, make the arguments const& when possible:
std::ostream &operator<<(std::ostream &out, person const &p) {
Secondly, make sure the streams flush to the buffer. I think it's good practice to limit the lifetime of the ostream or istream instances
Thirdly, choose a format that will be robust. Your sample already had bigger problems, when you had m_id = 1 and m_message = "123" (can you see it?).
In text formats you need either fixed-length fields or a delimiting protocol. Let's fix it:
std::ostream &operator<<(std::ostream &out, person const &p) {
return out << p.m_id << ";" << p.m_message.length() << ";" << p.m_message;
}
Now when reading it back you will see how much more precise you need to be:
std::istream &operator>>(std::istream &in, person &p) {
char separator;
size_t length;
bool ok = in >> p.m_id
&& in >> separator && separator == ';'
&& in >> length
&& in >> separator && separator == ';'
;
if (ok) {
p.m_message.resize(length);
in.read(&p.m_message[0], length);
p.m_message.resize(in.gcount());
}
// ensure the expected number of bytes were read
ok = ok && (p.m_message.length() == length);
if (!ok)
in.setstate(std::ios::failbit);
return in;
}
Yikes. Really? Yes really. At a minimum!
Do error handling
Full Demo
Live On Coliru
#include <boost/asio.hpp>
#include <iostream>
struct person {
int m_id;
std::string m_message;
};
std::ostream &operator<<(std::ostream &out, person const &p) {
return out << p.m_id << ";" << p.m_message.length() << ";" << p.m_message;
}
std::istream &operator>>(std::istream &in, person &p) {
char separator;
size_t length;
bool ok = in >> p.m_id
&& in >> separator && separator == ';'
&& in >> length
&& in >> separator && separator == ';'
;
if (ok) {
p.m_message.resize(length);
in.read(&p.m_message[0], length);
p.m_message.resize(in.gcount());
}
// ensure the expected number of bytes were read
ok = ok && (p.m_message.length() == length);
if (!ok)
in.setstate(std::ios::failbit);
return in;
}
int main() {
boost::asio::streambuf buf;
std::ostream(&buf) << person{ 1, "Hello World!" };
person received;
if (std::istream(&buf) >> received) {
std::cout << "ID: " << received.m_id << std::endl;
std::cout << "Message: " << received.m_message << std::endl;
} else {
std::cout << "Couldn't receive person\n";
}
}
Prints
ID: 1
Message: Hello World!
BONUS
C++14 added std::quoted:
#include <iomanip>
std::ostream &operator<<(std::ostream &out, person const &p) { return out << p.m_id << std::quoted(p.m_message); }
std::istream &operator>>(std::istream &in, person &p) { return in >> p.m_id >> std::quoted(p.m_message); }
Which, in this case, also does the job: Live On Coliru
From http://en.cppreference.com/w/cpp/string/basic_string/operator_ltltgtgt (emphasis and ellipsis mine):
2) ... reads characters from is and appends them to str ... until one
of the following conditions becomes true:
...
...
std::isspace(c,is.getloc()) is true for the next character c in is (this whitespace character remains in the input stream). ...
Basicaly what this means is that if you extract a string from an istream using operator >> it stops at white spaces.
If you want to get everything from the stream into your string there are plenty of questions asking that (Like this one or this one).
I'm trying to use fstream to write an object to a file and read it after but when I try to show the object read on the screen using cout the error message Segmentation fault: 11 appears. Someone could help me with this code? Thanks in advance!
Produto *p1 = new Produto(1, "Refrigerante");
cout << "Produto p1 (pre serializacao): (" << p1->codigo << ") " << p1->descricao << endl;
ofstream serializationWriter;
serializationWriter.open("myobject.dat", ios::binary);
serializationWriter.write((char *)&p1, sizeof(p1));
Produto *p2;
ifstream serializationReader;
serializationReader.open("myobject.dat", ios::binary);
serializationReader.read((char *)&p2, sizeof(p2));
cout << "Produto p2 (pos serializacao): (" << p2->codigo << ") " << p2->descricao << endl;
You need provide some serialization mechanism for class Produto. For example:
class Produto {
// ...
private:
std::string m_str;
private:
friend ostream& operator<<(ostream& stream, const Produto& obj);
friend istream& operator>>(istream& stream, Prodoto& obj)
};
ostream& operator<<(ostream& stream, const Produto& obj)
{
// Write all data to stream.
// ...
stream << obj.m_str;
return stream;
}
istream& operator>>(istream& stream, Prodoto& obj)
{
// Read all data from strem.
// ...
stream >> obj.m_str;
return stream;
}
And then use it as below:
Produto p1(1, "Refrigerante");
ofstream serializationWriter;
// ...
serializationWriter << p1;
Produto p2;
ifstream serializationReader;
// ...
serializationReader >> p2;
For more details see overload ostream istream operator