C++ binary file with records: string at beginning - c++

I am struggeling with reading from a binary file.
My binary file is made of records in the way like:
string - 5 x integers
The first string has differenct lengths, so I guess this may be my problem?
I try to read a record into a class which has the same type of attributes:
class Team
{
private:
string teamName;
int matchesPlayed;
int gamesWon;
int gamesLost;
int pointsWon;
int pointsLost;
public:
Team(string ="",int = 0,int = 0, int = 0, int = 0, int = 0);
~Team();
//void operator<();
void setTeamName(string);
void setMatchesPlayed(int);
void setGamesWon(int);
void setGamesLost(int);
void setPointsLost(int);
void setPointsWon(int);
void print();
};
I try to read in from another class:
Table::Table()
{
Team t1;
teams.push_back(t1);
ifstream inputFile;
inputFile.open("tabletennis.dta", ios::in | ios::binary);
if(!inputFile)
{
cout << "Datei konnte nicht geoeffnet werden!";
exit(1);
}
if(inputFile.good())
inputFile.read(reinterpret_cast<char*> (&t1), sizeof(Team));
t1.print();
}
Team::print() just prints out the content of its attributes. But the program crashes when I try to print the string.
I don't know what I may understood wrong.. but what I thought was:
Reading in to an Object with the same count and type of attributes is they way how to read a record set:
Team::Team(string teamName, int matchesPlayed, int gamesWon, int gamesLost, int pointsWon, int pointsLost)
{
setTeamName(teamName);
setMatchesPlayed(matchesPlayed);
setGamesWon(gamesWon);
setGamesLost(gamesLost);
setPointsWon(pointsWon);
setPointsLost(pointsLost);
}
Don't know for now..

Yep, if you want to do record-based I/O, then the records must really all have the same length. and record-based I/O is a rare occasion when using an array of char may be a better bet than a std::string. I would change this:
class Team
{
private:
string teamName;
int matchesPlayed;
int gamesWon;
int gamesLost;
int pointsWon;
int pointsLost;
to:
class Team
{
private:
char teamName[NAMESIZE];
int matchesPlayed;
int gamesWon;
int gamesLost;
int pointsWon;
int pointsLost;
You can then read and write:
Team t( .... ); // construct a team
os.write( (const char *) & t, sizeof( t ) );
and read:
Team t; // default construct empty team
is.read( (char *) & t, sizeof( t ) );

Nothing more to add to the answer of Neil but
I would suggest that you take a look at boost serialization.
If your file format is not fixed and you can easily change it, this will really help you to avoid a lot of traps in serialization.

Related

Segmentation Fault in memcpy operation of a struct

I am adding the header file and cpp file (it has main fucntion).
AuctionPrices.h
#ifndef AuctionPrices_h
#define AuctionPrices_h
/*
*
* class AuctionPrices - maintains Buy Order, Sell Order books
*/
#include <bits/stdc++.h>
#include <map>
//#pragma pack(1)
struct Order
{
char * itemId;
char * auctionId;
int Side;
};
class AuctionPrices
{
public:
virtual int AddNewOrder(char *itemId, char *auctionId, int Side, int Price) = 0;
virtual int DeleteOrder(char *itemId, char *auctionId) = 0;
virtual int Print() = 0;
};
class AuctionPrice_Imp : public AuctionPrices
{
public:
AuctionPrice_Imp();
~AuctionPrice_Imp();
std::map <int, Order, std::greater< int >> BuyMap;
std::map <int, Order, std::less< int >> SellMap;
int AddNewOrder(char *itemId, char *auctionId, int Side, int Price);
int DeleteOrder(char *itemId, char *auctionId);
int Print();
};
#endif
AuctionPrices_Imp.cpp
/**
* Auction Price Class implementation
* Constructor, AddNewOrder, DeleteOrder, Print
*
*/
#include <bits/stdc++.h>
#include <map>
#include "AuctionPrices.h"
using namespace std;
AuctionPrice_Imp::AuctionPrice_Imp()
{
}
AuctionPrice_Imp::~AuctionPrice_Imp()
{
}
int AuctionPrice_Imp::AddNewOrder(char *itemId, char *auctionId, int Side, int Price)
{
Order order;
memcpy(order.itemId, itemId, strlen(itemId)+1);
memcpy(order.auctionId, auctionId, strlen(auctionId)+1);
order.Side = Side;
if (Side == 1)
{
BuyMap.insert (std::pair<int,Order>(Price,order));
//buyLevels_.insert( std::pair< OfPrice, Level< OrderEntry > >( price, buyLevel ) );
}
else if (Side == 2)
{
SellMap.insert (std::pair<int,Order>(Price,order));
}
else
{
return 0;
}
return 1;
}
int AuctionPrice_Imp::DeleteOrder(char *itemId, char *auctionId)
{
return 0;
}
int AuctionPrice_Imp::Print()
{
std::map <int,Order,std::greater< int >>::iterator buy_it;
std::map <int,Order,std::less< int >>::iterator sell_it;
// Print Sell Map
for ( sell_it = SellMap.begin();sell_it != SellMap.end(); sell_it++)
{
std::cout << sell_it->first << '\t' << std::endl;
}
// Print Buy Map
for ( buy_it = BuyMap.begin();buy_it != BuyMap.end(); buy_it++)
{
std::cout << buy_it->first << '\t' << std::endl;
}
return 1;
}
int main()
{
AuctionPrice_Imp * auctionPrice_Imp = new AuctionPrice_Imp();
/*
AddNewOrder(“item1”, “auction1”, 1, 100)
AddNewOrder(“item1”, “auction2”, 1, 101)
AddNewOrder(“item2”, “order3”, 1, 99)
AddNewOrder(“item2”, “order4”, 2, 100)
*/
auctionPrice_Imp->AddNewOrder("item1", "auction1", 1, 100);
auctionPrice_Imp->AddNewOrder("item1", "auction2", 1, 101);
auctionPrice_Imp->AddNewOrder("item2", "order3", 1, 99);
auctionPrice_Imp->AddNewOrder("item2", "order4", 2, 100);
auctionPrice_Imp->Print();
}
When I am running the code its giving segmentation fault at the line:
memcpy(order.auctionId, auctionId, strlen(auctionId)+1);
Please anyone can help or correct the code.
The functions I am calling are supposed to add the orders to the Maps: BuyMap and SellMap. Once they have added to those map, I am using a print function to print the values.
Order order;
This creates a new Order object. Order does not have a constructor, so none of its class members, itemId, and auctionId, get initialized to point to anything. These pointers are uninitialized, random garbage. Immediately afterwards:
memcpy(order.itemId, itemId, strlen(itemId)+1);
memcpy(order.auctionId, auctionId, strlen(auctionId)+1);
Since neither itemId, nor auctionId, point to sufficient memory that are at least strlen(itemId)+1 or strlen(auctionId)+1 in size, respectively, this results in undefined behavior, and your crash.
In C++, before using a pointer, it is your responsibility to make sure that the pointer is valid, and points to the correct object, objects, or sufficiently-sized memory buffers. C++ will not do that for you, you have to do all that work yourself.
But if your intent is to write modern C++ code, it is much simpler just to use C++ classes, like std::strings instead of plain char * pointers. std::strings automatically handle all these low-level details, manage memory properly, without making it your responsibility to do so. You will find a complete description of std::string and many examples of using it in your C++ textbook.
You should use std::string to avoid having to deal with low level issues of pointers and memory allocation. These are the issues that you are getting wrong in your code. Here's your code rewritten to use std::string
struct Order
{
std::string itemId;
std::string auctionId;
int Side;
};
int AuctionPrice_Imp::AddNewOrder(std::string itemId, std::string auctionId, int Side, int Price)
{
Order order;
order.itemId = itemId;
order.auctionId = auctionId;
order.Side = Side;
See how easy that is? The code to use std::string is no different to the code that handles int.

errror: invalid conversion from 'const char*' to 'int'

I am trying to add to a class a person's day, month and year of birth. As of now, i am at trying to include the day of birth, had lots of errors, managed to get rid of most of them but i still have this one left(at first, i included at the same time the day, month and year of birth but i had many erros so i decided to try and fix at least one of them). In the code i also have the birth date as a char and that works fine but i need those values to work with them later.
#include <iostream>
#include <cstring>
using namespace std;
class Persoana
{
private:
char nume[20];
char data_nastere[20];
int zi;
public:
Persoana(char *nume="", char *data_nastere="", int zi="");//this is where i have the error
void setNume(char *nume);
char* getNume();
void setDataNastere(char *data_nastere);
char* getDataNastere();
void setZi(int zi);
int getZi();
void afisare();
};
Persoana::Persoana(char *nume, char *data_nastere, int zi)
{
setNume(nume);
setDataNastere(data_nastere);
setZi(zi);
}
void Persoana::setNume(char *nume)
{
strcpy(this->nume, nume);
}
char* Persoana::getNume()
{
return nume;
}
void Persoana::setDataNastere(char *data_nastere)
{
strcpy(this->data_nastere, data_nastere);
}
char* Persoana::getDataNastere()
{
return data_nastere;
}
void Persoana::setZi(int zi)
{
this->zi=zi;
}
int Persoana::getZi()
{
return zi;
}
void Persoana::afisare()
{
cout<<"Nume: "<<nume<<endl;
cout<<"Data nasterii este: "<<data_nastere<<endl<<endl;
cout<<zi<<endl;
}
int main()
{
Persoana p[] = {Persoana("Calin Dorina", "12 02 2000", 12), Persoana("Mihaela Banu", "25 04 2001", 25)};
p[0].afisare();
//p[1].afisare();
}
You try to assign a pointer to literal string (it's pointer to const char which is fist letter in this string) to the integer property z in constructor: int zi="". C++ hasn't default conversion from const char* to int. You should use integer default values for integer properties.
One of you said to declare int zi=0 and thats the right answer. I tried doing it before but where i declared the private variables. Thanks for helping!
In case someone else has this problem, here it is how its supposed to be:
Persoana(char *nume="", char *data_nastere="", int zi=0);

Simplest way to read data from a txt file

I want to store the contents of a .txt file as attributes of different objects which I can then store in a vector. Is there a simple way to do this.
My txt file looks like this:
a0 0 4 0 10
a1 0 3 0 20
a2 0 2 0 30
I tried to do it like this but i get an error.
class process {
public:
std::string name;
int arrivalTime;
int priority;
int age;
int ticketsReq;
int time;
process(std::string name, int arrivalTime, int priority, int age, int ticketsReq) {
this->name = name;
this->arrivalTime = arrivalTime;
this->priority = priority;
this->age = age;
this->ticketsReq = ticketsReq;
this->time = 0;
}
};
int main() {
std::ifstream theFile("input.txt");
int i = 0;
std::vector<process> a;
std::string nameT;
int arrivalTimeT;
int priorityT;
int ageT;
int ticketsReqT;
int timeT;
while(theFile>>nameT>>arrivalTimeT>>priorityT>>ageT>>ticketsReqT){
a[i] = process (nameT,arrivalTimeT,priorityT,ageT,ticketsReqT);
i++;
}
}
Okay, I see at least one problem.
First, vector assumes you call push_back to add elements to the vector. You can do vector[index] to access an element once it exists. But you're going to get a range problem with that.
Second, this line doesn't make sense:
a[i] = process (nameT,arrivalTimeT,priorityT,ageT,ticketsReqT);
At the point you do this, you don't have a "this" for process. You would need to do something like:
process myObj(nameT,arrivalTimeT,priorityT,ageT,ticketsReqT);
a.push_back(myObj);
As a side-point, I personally never store objects in std::vector. I store pointers to objects. I don't know if someone else can comment on this, but consider what happens. You may want to write a simpler example to test that.

Dynamic memory allocation to array of pointers to object

I have a class named Student
class Student
{ string name;
unsigned long int ID ;
string email;
unsigned short int year;
public :
Student() // Constructor
string getName(void);
unsigned long int getID(void);
string getEmail(void);
unsigned short int getYear(void);
{
and another class named eClass
class eClass {
private:
string eclass_name;
Student* students[100];
unsigned int student_count;
public:
eClass(string name)
{
student_count =0 ;
eclass_name = name ;
}
bool exists(Student obj)
{
unsigned long int code = obj.getID();
bool flag = TRUE ;
for (unsigned int i = 0 ; i<=student_count ; i++ )
{
unsigned long int st = (*students[i]).getID();
if (code==st)
{
flag = FALSE;
}
}
return flag;
}
void add(Student& obj)
{
bool res = exists(obj);
if (res)
{
students[student_count] = new Student(); //probably the problem is here
*students[student_count] = obj ;
student_count++ ;
}
}
string getEclassName(void) { return eclass_name; }
unsigned int getStudentCount(void) { return student_count; }
Student getStudent(int i) { return *students[i-1]; }
};
The statement Student* students[100]; must look exactly like this . For example I can't write something like this: Student* students[100]={} ;
And main() looks like this
int main()
{
Student JohnDoe("John Doe", 12345, 2, "johndoe#gmail.gr");
eClass Cpp("C++");
Cpp.add(JohnDoe);
}
Basically I have an array of pointers to Student objects and I want to allocate dynamically memory every time I want to add a new Student object.
When I compile I get no errors but when I try to run the program the only thing I get is "Program_name.exe" stopped running...
I'm pretty sure the problem has to do with memory allocation but I'm not able to find it and solve it.
Any suggestions ?
The main bug in exists was the loop went one too far, using an uninitialized pointer. But also it is very bad style for exists to take its input by value. Fixing both of those:
bool exists(Student const& obj)
{
unsigned long int code = obj.getID();
bool flag = TRUE ;
for (unsigned int i = 0 ; i<student_count ; i++ )
{
unsigned long int st = (*students[i]).getID();
if (code==st)
{
flag = FALSE;
}
}
return flag;
}
You should declare getID() const inside student in order to be able to code exists correctly.
unsigned long int getID() const;
First, you should initialize all of your student pointers to either NULL or nullprt. This is not strictly needed but is a very good habit to get into. You'll thank yourself later.
Second, why are you returning false if the student exists? Kind of confusing I'd imagine. Also, you can use the break statement after you find your student exists; no need to check the rest of them.
Also, on your add, you may want to check to ensure you don't have MORE than 100 students. This will overwrite memory and bad things will happen.

C++ Struct defined data passing. Simple answer im sure

I am sure this is a very simple fix and I feel dumb asking it but here it goes.
I need help with a struct and passing info from a gather function to a save or set function, and then passing it again to another function for further use.
Basically, it looks like this to start. I'll just add short snips of the code. All can be provided if you would like to see it.
I right now am just looking for the proper way to pass struct defined data from get.... to set.... functions.
struct printype
{
char dots[8][15];
int unknown15; // can have values of 0..127
string serial11_14; // 8 characters 00000000...99999999
int year8; // without century, 0..99
int month7; // 1..12
int day6; // 1..31
int hour5; // 0..23
int minute2; // 0..59
};
int getunknown15(); // prototypes
int setunknown15(int);
then we have a simple main.
int main()
{
printype pt;
pt.unknown15=getunknown15();
pt.unknown15=setunknown15(12);
pt.serial11_14=getserial11_14();
pt.serial11_14=setserial11_14("12345678");
pt.year8=getyear8();
pt.year8=setyear8(44);
pt.month7=getmonth7();
pt.month7=setmonth7(11);
pt.day6=getday6();
pt.day6=setday6(12);
pt.hour5=gethour5();
pt.hour5=sethour5(12);
pt.minute2=getminute2();
pt.minute2=setminute2(23);
cout <<"-----------------------------------------------------"<<endl;
cout <<" Let's Get Started"<<endl;
cout <<"-----------------------------------------------------"<<endl;
setup(pt.dots); // sets up the array
dpinfo(pt); // prints out the final array
ftarray(pt);
spar(pt.dots);
darray(pt.dots);
}
and finally the get and set array functions.
int getunknown15()
{
printype tem;
cout <<"-----------------------------------------------------"<<endl;
cout <<" Enter the Unkown Variable (0-127): ";
cin >>tem.unknown15;
cout <<"-----------------------------------------------------"<<endl;
return tem.unknown15;
}
next is
int setunknown15(int tem)
{
printype pp;
if (tem>127||tem<0)
{
cout << "Error" << endl;
return 0;
}
else
{
pp.unknown15 = tem;
return pp.unknown15;
}
}
I hope this isn't too much to read and understand
Anyway, I know this has a really simple answer but my brain just isn't working right now.
Edit: As StilesCrisis stated, Send struct as parameter is quiet stupid in this case. better use a const reference.
Well, I am not sure if I understand your question correctly. You can simply send struct to another function as parameter, or as a pointer.
like:
void SetStruct(const printype& var);
printype GetStruct();
Is it what you are looking for?
Please use the following access to the your fields, (by reference):
struct printype *myPtr = new printype;
myPtr->day6 = 43;
When use pointer instead of a normal variable, you should use -> instead . to access your fields.
I know this is kind of old but I thought I should give it a shot, since you are using C++ and it looks like you are trying to use some OO practices (I think), you don't need to start with a struct, even though OO principles can be applied using them as well though not as elegantly.
you can define your class header file as such.
#ifndef PRINTYPE_H
#define PRINTYPE_H
#include <string>
using namespace std;
class printype
{
private: // we always want to declare our member fields private for safety/managements reasons, no one will be able to access them outside.
char dots[8][15];
int unknown15; // can have values of 0..127
string serial11_14; // 8 characters 00000000...99999999
int year8; // without century, 0..99
int month7; // 1..12
int day6; // 1..31
int hour5; // 0..23
int minute2; // 0..59
void init(); // This is the method we use to initialize our starting state.
public: // This is our public methods, how people deal with/get/set our state.
printype(); // This is our default constructor
printype(const printype& print_type); // This our copy constructor
virtual ~printype(); // This is our destructor, its virtual, making safer for inheritance.
// This is our setters/getters
void setUnknown(int unknown);
int getUnknown();
void setYear(int year);
int getYear();
void setMonth(int mont);
int getMonth();
// and well you get the idea, you can add more methods.
};
#endif
and the accompanying class source file with your functions implementation
printype::printype()
{
this->init(); // Initialize all your vatiables, safer to just define a function to this.
}
printype::printype(const printype& orig) // copy constructor
{
this->setUknown(orig.getUnknown());
this->setDay(orig.getDay());
this->setDots(orig.getDots());
// you get the idea ...
}
printype::~printype()
{
// Have anything you need to do before destroying the object.
}
void printype::init()
{
this->setUnknwon(0);
this->setyear(0);
this->setMonth(1);
char dots[8][15] = {'\0'};
this->setDots(dots);
// you get the idea, you want to initialize all your variables since, for the most part they initially hold garbage.
}
void printype::setUnknown(int unknown)
{
if (unknown >= 0 && unknown < 127)
this->unknown15 = unknown;
else
error("Expecting unknown to be between 0 and 127"); // error should probably print the error and/or exit(-1) up to u
}
int printype::setYear(int year)
{
if (year >= 1 && year <= 99)
this->year8 = year;
else
error("Expecting year between 0 and 99"); // you may want to implement an error function!
}
int printype::getYear()
{
return this->year8;
}
void printype::setDots(char dots[8][15])
{
// you may want to do some verifications
memcpy(this->dots, dots, sizeof(dots));
}
void printype::setDots(char **dots) // this is a bit unsafe, use at your own risk.
{
if (dots)
{
unsigned int index = 0;
for (index = 0; index < 8; index++)
if (dots[index])
memcpy(this->dots[index], dots[index], 15);
else
error("dots required pointer ...");
}
else
error("dots required pointer ...");
}
char **getDots() // We will be returning a copy, we don't want the internal state to be affected, from outside, by using reference or pointers.
{
char **dots = new char*[8];
unsigned int index = 0;
for (index = 0; index < 8; index++)
{
dots[index] = new char[15];
memcpy(dots[index], this->dots[index], 15);
}
return dots;
}
// and well you get the idea ...
to use your class
printype *print_type_p = new print_type();
// or
printype pront_type_p();
// use the different public method to update the internal state.
print_type_p->setYear(3);
// or
print_type.setYear(3);
print_type_p->getYear();
// and so on.