Exception in homemade string class - c++

I wrote a C++ class named DCstring similar to String class in Java.
class DCstring
{
public:
TCHAR *string;
DCstring();
DCstring(TCHAR * str);
DCstring in();
}
DCstring::DCstring()
{
string=NULL;
}
//constructor to initialize
DCstring::DCstring(TCHAR* temp)
{
_TINT i=0;
string=(TCHAR*)malloc(_tcslen(temp)*sizeof(TCHAR)+1);
for(;i<_tcslen(temp);i++)
string[i]=temp[i];
string[i]=0;
}
//to get input from user
DCstring DCstring::in()
{
wprintf(L"\n Enter the string :");
TCHAR arr[200],*s;
_getts(arr);
_TINT i=0;
string=(TCHAR*)realloc(string,_tcslen(arr)*sizeof(TCHAR)+1);
for(;i<_tcslen(arr);i++)
string[i]=arr[i];
string[i]=0;
return(*this);
}
This works fine.
I use this DCstring variable inside a struct and reads & writes that struct object into &from a file using fwrite & fread functions.
typedef struct Stud
{
DCstring name;
}stud;
void InsertToFile(stud *temp,FILE *file)
{
(temp->name)=DCstring();
fflush(stdin);
temp->name=(temp->name).in();
fseek(file,0,SEEK_END);
fwrite(&(*head),sizeof(stud),1,file);
}
void Show(stud *temp,FILE *file)
{
rewind (file ) ;
fread ( &temp,sizeof(stud), 1, file ) ;
wprintf ( L"\n%s",temp->name ) ;
}
This code can read and write data for the 1st time.when I reexecute the code and call Show(stud *temp,FILE *file) function,it throws an runtime error/exception.
"Unhandled exception at 0x77c815de in StudentRecord.exe: 0xC0000005: Access violation reading location 0x002850a8".
seems like problem in memory.Help me out.

Apart from the poor implementation of your DCString class (exposed instance variables, lack of destructor, fixed-sized input buffer, and some more) you have failed to understand that writing an instance of your struct stud won't, in fact, write the contents of the data pointed to by stud.name.string.
struct stud contains an instance of DCString however the memory used to store the string data is on the heap (which you allocated using malloc()); your code is writing the pointer to the allocated memory, which will be meaningless when you read it back in (certainly in a different session).
You need to provide a read/write DCString method, which is passed a FILE * (better would be to use istream and ostream, given this is C++) which reads/writes the string contents, allocating new memory during the read.

The problem is here:
public:
TCHAR *string;
This writes out a pointer to the string, so when you read back in you get a pointer that doesn't point to any data, thus your access violation. This question, for instance, discusses serialisation, which is what you probably want to do.
Furthermore:
fflush(stdin);
Is undefined behaviour.
Yet furthermore, you should really use C++ std::string and std::i/ofstream.
EDIT I just noticed:
wprintf ( L"\n%s %d %c",temp->name ) ;
You don't have anything matching the %d and %c parameters.

Related

Use a string as a char

I have been given this definitions, the function should return what is in info->phrase. However info->phrase can contain a string in which case I can only make it return the first char on info->phrase. Is there a way to make a string compatible with the char type? I am new to c++.
struct rep_info {
int num;
char *phrase;
};
I´ve tried few thing but get type errors, this was my latest attempt
char *phrase_info(rep_info info) {
char text[std::strlen(info->phrase) + 1];
text = info->phrase;
return text;
}
Since you said you have been given these definitions, let's fix the problem with the current setup first. Looking at your function, you are trying to copy into this local array (incorrectly I might add), and return this local variable. There are a number of things wrong with this, including the syntax and the fact that the local variable is destroyed when the function exits.
If you just need to get the value of the phrase member variable, the simplest solution would be to just access the member variable directly and return it:
char *phrase_info(rep_info info) {
return info.phrase; //since info is not a pointer, use the '.' accessor
}
If you mean to pass a pointer to the function, you would re-write it like this:
char *phrase_info(rep_info *info) {
return info->phrase;
}
But it seems like you feel the need to copy the contents of info->phrase into a new memory space? If so, then you would do something like this where you first allocate new memory and return this buffer:
char *phrase_info(rep_info *info) {
char *buf = new char[std::strlen(info->phrase) + 1];
std::strcpy(buf,info->phrase); //copies info->phrase into buf
return buf;
}
You would then need to use delete on the returned memory value to clean up the memory allocated by new, otherwise you will have a memory leak.
Overall, all the above solution would potentially solve the problem given some parameters you haven't made clear. To round this out, this should be written more like:
class rep_info {
private:
int num;
std::string phrase;
public:
rep_info(int n, std::string p) : num(n), phrase(p) {}
std::string get_phrase() { return phrase; }
// other functions
};
//later in the code
rep_info info(...);
info.get_phrase();
Ideally, you would wrap these member variables into their own object with corresponding member functions that can get and set these values. Moreover, for handling strings in C++, std::string is the preferred option for storing, copying, modifying, etc. strings over the older char * C-style string.

Vector iterator is not dereferencable, while try to read from file

I'm writing data (structure) into file using vector, and when I attempt to retrieve data using vector iterator and it gives me: "Vector iterator is not dereferenceable."
This is my code:
void CProgram_1_STLDlg::OnBnClickedBtnView()
{
// TODO: Add your control notification handler code here
CFile file;
CFileException e;
studentVector::iterator sit;
studentVector::iterator sBegin = sVector.begin();
studentVector::iterator sEnd = sVector.end();
CString path = _T("D:\\Student.txt");
if ( file.Open(path, CFile::modeRead, &e) ) {
while ( file.Read( (char *)&sVector, sizeof(sVector)) ) {
AfxMessageBox(_T("File opened in read mode."), MB_ICONINFORMATION);
AfxMessageBox(_T("ID:\t")+sit->id+L"\nName:\t"
+sit->name+L"\nMarks:\t"+sit->marks+L
"\nPercentage:\t"+sit->per+L"\nState:\t"+sit->state);
sit++;
}
//file.Read( (char *)&sData, sizeof(sData));
/*for ( sIterator = sVector.begin(); sIterator != sVector.end(); sIterator++ ) {
//AfxMessageBox(_T("ID:\t")+sIterator->id+L
"\nName:\t"+sIterator->name+L"\nMarks:\t"
+sIterator->marks+L"\nPercentage:\t"+sIterator->per+L
"\nState:\t"+sIterator->state);
//AfxMessageBox(_T("Hello..Testing...!"));
}
*/
} else {
AfxMessageBox(_T("Error! Unable to open file."), MB_ICONERROR);
}
}
Now I don't know how to resolve this error.
Note: Some of links I refer which google gave me, but I couldn't able to solve my problem.
You cannot simply overwrite the memory of a vector. That is pretty much guaranteed to corrupt your process.
Furthermore, you never assign anything to sit and yet expect it to contain something sensible.
You need to parse the data in Student.txt and use vector's member functions to fill it with sensible data. The assignment will probably tell you what the file looks like so that you can parse it.
A simple vector like
vector<char> cvec
could be overwritten
so something like
vector<char> cvec;
cvec.resize(100);
for(char i=0;i<100;i++)
cvec[i]=i;
will work.
If you resize to correct size. Otherwise you will corrupt memory
sizeof(sVector) will deliver the size of the vector class.
this is not related to the data since data inside the vector class is nothing more than a pointer.
example:
class simpleVector;
{
public:
simpleVector(unigned int size)
{
p=new int[size];
}
int* p;
}
func()
{
simpleVector v1(10);
simpleVector v2(100000);
printf("size v1= %d, Size v2= %d", sizeof(v1),sizeog(v2));
}
I have not checked, what sizeof will deliver for this class, but it definitely will be constant. Independent from the size that is given to constructor
An Iterator is an accessor to the Vector
but it needs to be initialized.
In the code above sit is not assigned to something. So you are not able to access something valid.
from the code line
AfxMessageBox(_T("ID:\t")+sit->id+L"\nName:\t"+sit->name+L"\nMarks:\t"+sit->marks+L"\nPercentage:\t"+sit->per+L"\nState:\t"+sit->state);
I see the vector shall contain a complex data type build from several strings.
so a vector element probably looks like
class student
{
std::string id;
std::string name;
std::string marks;
std::string per;
std::string state;
};
this is in minimum the information hold by each vector element.
usually strings have the property to have different length.
While id might be always of same length name probably don't.
Since it is not fixed length
even
file.Read( (char *)&sVector, sizeof(student))
would not work.
so I would suggest to add a reader to the 'Student' Class:
class student
{
std::string id;
std::string name;
std::string marks;
std::string per;
std::string state;
bool ReadElemFromFile(CFile& file)
{
id=ReadStringFromFile(file);
name=ReadStringFromFile(file);
marks=ReadStringFromFile(file);
per=ReadStringFromFile(file);
state=ReadStringFromFile(file);
if(id.empty()||name.empty()||marks.empty()||per.empty()||state.empty())
return false;
return true;
}
std::string ReadStringFromFile(CFile% file)
{
char c;
std::string s;
do
{
file.read(&c,1);
s+=c;
}
while(c!='\0')
return s;
}
};
I know reading that way is not the most performant way to do it, but it shows,that the string terminator stored to file indicates the length of each string
now back to your code
void CProgram_1_STLDlg::OnBnClickedBtnView()
{
// TODO: Add your control notification handler code here
CFile file;
CFileException e;
student* sit=new Student;
studentVector.clear();
CString path = _T("D:\\Student.txt");
if ( file.Open(path, CFile::modeRead, &e) ) {
while ( sit->ReadElemFromFile(CFile& file)) {
AfxMessageBox(_T("File opened in read mode."), MB_ICONINFORMATION);
AfxMessageBox(_T("ID:\t")+sit->id+L"\nName:\t"+sit->name+L"\nMarks:\t"+sit->marks+L"\nPercentage:\t"+sit->per+L"\nState:\t"+sit->state);
studentVector.push_back(*sit);
}
} else {
AfxMessageBox(_T("Error! Unable to open file."), MB_ICONERROR);
}
delete stud;
}
..."attempt to retrieve data using vector iterator and it gives me Vector iterator is not dereferenceable"...
Iterators are pointer-like objects, however unlike raw pointers, they prevent dereferencing (accessing of the value they point to) if they are "dangling".
In your case iterator sit is not initialized, not as, for example iterator sBegin = sVector.begin();, that is assigned to point to the beginning of the vector sVector.
Thus when you try to access an iterator that does not point to a valid value, you get an error.
In addition to that, to store an element to a vector you should use its member functions, not passing its address, as you do in your while loop.

Access violation writing location error when i try to read from file

this is where i write to a file ->
void Supermarket_Billing_System::Add_and_WriteNewProduct(Product P)
{
ofstream fl;
fl.open("ProductList", ios::out | ios::binary);
fl.write((char *) &P, sizeof(P));
fl.close();
}
this is where i read from a file ->
void Supermarket_Billing_System::Read_DisplayProductFromProductList()
{
Product P;
int x;
ifstream fp;
fp.open("ProductList", ios::in);
fp.seekg(0, ios::beg);
fp.read((char *) &P, sizeof(P));
x = P.GetProduct_qty();
fp.close();
}
Product class looks like this ->
class Product
{
private:
long int Product_no;
std::string Product_name;
double Product_price;
int Product_qty;
double Product_tax;
double Product_dis;
public:
//Constructor
Product();
Product(long int, string, double, int, double, double);
//All Getters methods
long int GetProduct_no();
string GetProduct_name();
double GetProduct_price();
int GetProduct_qty();
double GetProduct_tax();
double GetProduct_dis();
//All Setters methods
void SetProduct_no(long int);
void SetProduct_name(string);
void SetProduct_price(double);
void SetProduct_qty(int);
void SetProduct_tax(double);
void SetProduct_dis(double);
void Accept_Product();
void Accept_ProductForBilling();
void Display_Product();
};
When i try to read from the file by calling Read_DisplayProductFromProductList() it gives me error ->
Unhandled exception at 0x6803ad54 (msvcp100d.dll) in Supermarket_Billing_System.exe: 0xC0000005: Access violation writing location 0xfeeefeee.
Your Product class is not trivially copyable due to the std::string member; you are not writing the actual string that Product_name holds in your write method, only the binary representation of a std::string, and the internal string pointer will almost certainly point to an invalid location when you read. Either way attempting to perform a bytewise copy of a non-trivially copyable class is undefined behavior.
You also haven't passed the binary flag when you open your file for reading
fp.open("ProductList", ios::in);
which will cause issues on Windows if there are any \r\n (0x0A 0x0D) sequences in the file you are reading.
You will either need to use a char array for your string, or manually handle the serialization of each member. The simplest way would be to use stream friend functions to write your object to a plain text file
I believe you shouldn't read into std::string like if it were a POD (plain old data). std::string Product_name is a member of your Product class and when you read from the stream, it likely spoils the string.
Similarly, you shouldn't write std::string like that (as part of Product).
I faced a similar issue, when i did write operation on a file using ofstream in a gSOAP client. However when i switched to FILE (stdio.h) and fwrite() the access violation error was gone!
It may because the open file error. You can print the return value to see if it is NULL.
When you compile your code.
Pay attention to the warning message. Sometimes, it may just a warning when you compiler, but got a crash when you run it.

Saving a game state using serialization C++

I have a class called Game which contains the following:
vector<shared_ptr<A>> attr; // attributes
D diff; // differences
vector<shared_ptr<C>> change; // change
My question is, how can I write these (save) to a file and read/load it up later?
I thought about using a struct with these in it, and simply saving the struct but I have no idea where to start.
This is my attempt so far, with just trying to save change. I've read up a lot on the issue and my issue (well one of them, anyway) here seems to be that I am storing pointers which after closing the program would be invalid (compounded by the fact that I also free them before exiting).
/* Saves state to file */
void Game::saveGame(string toFile) {
ofstream ofs(toFile, ios::binary);
ofs.write((char *)&this->change, sizeof(C));
/* Free memory code here */
....
exit(0);
};
/* Loads game state from file */
void Game::loadGame(string fromFile) {
ifstream ifs(fromFile, ios::binary);
ifs.read((char *)&this->change, sizeof(C));
this->change.toString(); // display load results
};
Can anyone guide me in the right direction for serializing this data? I'd like to use only standard packages, so no boost.
Thanks.
I have no idea how is implemented classes A, C or D, but that is the first question: how to serialize an object of that class. For the C case, you need to implement something like this:
std::ostream& operator <<(std::ostream& os, const C& c) {
// ... code to serialize c to an output stream
return os;
}
std::istream& operator >>(std::istream& is, C& c) {
// ... code to populate c contents from the input stream
return is;
}
or, if you prefer, create a write() and read() function for that class.
Well, if you want to serialize a vector<shared_ptr<C>> looks obvious you don't want to serialize the pointer, but the contents. So you need to dereference each of those pointers and serialize. If the size of the vector is not known before loading it (i.e., is not always the same), you'll need to store that information. Then, you can create a pair of functions to serialize the complete vector:
std::ostream& operator <<(std::ostream& os, const std::vector<std::shared_ptr<C>>& vc) {
// serialize the size of the vector using << operator
// for each element of the vector, let it be called 'pc'
os << *pc << std::endl; // store the element pointed by the pointer, not the pointer.
return os;
}
std::istream& operator >>(std::istream& is, std::vector<std::shared_ptr<C>>& c) {
// read the size of the vector using >> operator
// set the size of the vector
// for each i < sizeo of the vector, let 'auto &pc = vc[i]' be a reference to the i-th element of the vector
C c; // temporary object
is >> c; // read the object stored in the stream
pc = std::make_shared<C>(c); // construct the shared pointer, assuming the class C has copy constructor
return is;
}
And then,
/* Saves state to file */
void Game::saveGame(string toFile) {
ofstream ofs(toFile);
ofs << change;
....
};
/* Loads game state from file */
void Game::loadGame(string fromFile) {
ifstream ifs(fromFile);
ifs >> change;
};
I know there are a lot of things you still need to resolve. I suggest you to investigate to resolve them so you understand well how to solve your problem.
Not only are you saving pointers, you're trying to save a shared_ptr but using the wrong size.
You need to write serialization functions for all your classes, taking care to never just write the raw bits of a non-POD type. It's safest to always implement member-by-member serialization for everything, because you never know what the future will bring.
Then handling collections of them is just a matter of also storing how many there are.
Example for the Cs:
void Game::save(ofstream& stream, const C& data)
{
// Save data as appropriate...
}
void Game::saveGame(string toFile) {
ofstream ofs(toFile, ios::binary);
ofs.write((char *)change.size(), sizeof(change.size());
for (vector<shared_ptr<C>>::const_iterator c = change.begin(); c != change.end(); ++c)
{
save(ofs, **c);
}
};
shared_ptr<C> Game::loadC(ofstream& stream)
{
shared_ptr<C> data(new C);
// load the object...
return data;
}
void Game::loadGame(string fromFile) {
change.clear();
size_t count = 0;
ifstream ifs(fromFile, ios::binary);
ifs.read((char *)&count, sizeof(count));
change.reserve(count);
for (int i = 0; i < count; ++i)
{
change.push_back(loadC(ifs));
}
};
All the error handling is missing of course - you would need to add that.
It's actually a good idea to at least start with text storage (using << and >>) instead of binary. It's easier to find bugs, or mess around with the saved state, when you can just edit it in a text editor.
Writing your own serialization is quite a challenge. Even if you do not use boost serializatoin I would recommend you learn how to use it and comprehend how it works rather than discovering it yourself.
When serializing you finally end up with a buffer of data of which content you have very vague idea. You have to save everything you need to be able to restore it. You read it chunk by chunk. Example (not compiled, not tested and not stylish ):
void save(ostream& out, const string& s)
{
out << s.size();
out.write(s.c_str(), s.size());
}
void load(istream& in, string& s)
{
unsigned len;
in >> len;
s.resize(len);
in.read((char*)s, len);
}
struct Game
{
void save(ostream& out)
{
player.save(out);
};
void load(istream& in)
{
player.load(in);
}
};
struct Player
{
void save(ostream& out)
{
// save in the same order as loading, serializing everything you need to read it back
save(out, name);
save(out, experience);
}
void load(istream& in)
{
load(in, name);
load(in, experience); //
}
};
I do not know why you would do it to yourself instead of using boost but those are some of the cases you should consider:
- type - you must figure out a way to know what "type of change" you actually have there.
- a string (vector, whatever) - size + data (then the first thing you read back from the string is the length, you resize it and copy the "length" number of characters)
- a pointer - save the data pointed by pointer, then upon deserialization you have to allocate it, construct it (usually default construct) and read back the data and reset the members to their respective values. Note: you have to avoid memory leakage.
- polymorphic pointer - ouch you have to know what type the pointer actually points to, you have to construct the derived type, save the values of the derived type... so you have to save type information
- null pointer... you have to distinguish null pointer so you know that you do not need to further read data from the stream.
- versioning - you have to be able to read a data after you added/removed a field
There is too much of it for you to get a complete answer.

Reading Binary Data with streambuf in C++ through a Class

Im am a c programmer trying to begin a new phase of my life in c++ (i know i am still using printf below, but that because formatting is so easy). I am looking to print out the first byte of a datafile from a member function of an object. I think my streambuffer is being destroyed before I can read it's data but I'm lost as to what to do.
My class looks like the following
class MyParser {
MyParser(string filepath);
void readHeader();
streambuf *pbuf;
long size;
}
My constructor opens the file, gets the buffer out, outputs the first byte and returns. (I think pbuf is dying at the end of this code). This code outputs First Byte (in constructor): 0x8C
MyParser::MyParser(string filepath) {
ifstream file(filepath.c_str(), ios::in | ios::binary)
pbuf = file.rdbuf();
size = pbuf->pubseekoff(0,ios::end,ios::in);
pbuf->pubseekpos(0,ios::in);
unsigned char byte = pbuf->sgetc();
printf("First Byte (in constructor): 0x%02X\n", byte);
return;
}
My read header is dumping the first byte, but based on the output all is see is First Byte (in readHeader): 0xFF
void MyParser::readHeader() {
unsigned char byte = pbuf->sgetc();
printf("First Byte (in readHeader): 0x%02X\n", byte);
}
My main simply creates a parser and tries to readHeader
void main() {
MyParser parser("../data/data.bin");
parser.readHeader();
}
I think the solution to my problem is to create a new streambuffer but new streambuf(file.rdbuf()) isn't working for me. Any advice?
Your program has undefined behavior: the stream buffer you keep is owned by the std::ifstream you open in body of you constructor. When this object dies, the stream buffer is released as well. The easiest approach to avoid this problem is to have your std::ifstream be a member of your class: this binds the life-time of the stream to your object. It may also be easier to use the std::istream interface for your parsing rather than the somewhat awkward std::streambuf interface.
If you really want to just use a stream buffer, you can allocate a std::filebuf using new filebuf and the open() the file stream directly. To keep a pointer to it, you would probably use std::unique_ptr<std::filebuf> (or std::auto_ptr<std::filebuf> if you are not using C++ 2011). Using the pointer class arranges for automatic release of the object. Of course, the pointers would still be members of your class to get the life-times right.
Your attempt to copy a stream buffer didn't work because stream buffers are not copyable. You'd need to create the file buffer directly:
MyParser::MyParser(std::string const& filename)
: pbuf(new std::filebuf)
{
this-pbuf->open("whatever", std::ios_base::in);
...
}
You need some new C++ teaching material, because (sorry) but this is just so wrong. You need to declare the filestream as a member, there's no need for any new anywhere in this program, and pretty much nobody, ever, needs to deal with streambuf.
class MyParser {
std::ifstream file;
public:
MyParser(string filepath) {
file.open(filepath, std::ios::in | std::ios::binary );
char byte;
file.read(sizeof(byte), &byte);
printf("First Byte (in constructor): 0x%02X\n", byte);
}
void readHeader() {
char byte;
file.read(sizeof(byte), &byte);
printf("First Byte (in readHeader): 0x%02X\n", byte);
}
};