Why does this cpp program fail? - c++

Note: While I was debugging, I found that until the last line, the program run normally, but when going by the last bracket, a mistake window would pop up. I'm not quite familiar with C++ so I couldn't locate the problem. Please help!
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
class test {
public:
int x;
void add_list(int);
void display();
private:
vector<int> list;
};
void test::add_list(int op)
{
list.push_back(op);
}
void test::display()
{
cout << x << endl;
for (unsigned int i=0;i<list.size(); i++)
cout << "->" << list[i];
cout << endl;
}
int main (void)
{
test test1;
test1.x = 3;
test1.add_list(2);
test1.add_list(4);
int size = sizeof (test1);
ofstream fout ("data.dat", ios_base::binary);
fout.write((char *)&test1, size);
fout.close();
ifstream fin ("data.dat", ios_base::binary);
test test2;
fin.read((char *)&test2, size);
test2.display();
fin.close();
return 0;
}

These lines
fout.write((char *)&test1, size);
and
fin.read((char *)&test2, size);
won't work because the test class contains objects that contain pointers. std::list will allocated extra memory using new to store items that are pushed on to it. It will then keep pointers to those items. When you write the object to disk, it will still contain those pointers to memory. When you load the object back again, the pointers will contain the same value, but your program may not have the same memory allocated and certainly won't have it allocated for the object.
In your case test2 appears to work because its internal pointers end up being the same as test1, however when you program finishes, the test1 destructor releases the memory that it allocated, then the test2 destructor tries to release the same memory, leading to your error.
To fix it, you should change your code to write the object in a defined format that doesn't use pointers (e.g. write out the item count followed by each items integer value). Then read them in the same way. One simple fwrite won't be able to do it.

Related

Pointer Array outputting integer variables without issue, but strings are all empty

I am a C++ novice and have an assignment using Oldie McOldSchool arrays and pointers. I have looked at this specific problem for about 8-12 cumulative hours now, kind of want to shove my face into a brick wall and don't really know what to think at this point. I am hoping from help from the experts here at SO!
I have the following class
#include <iostream>
#include <string>
using namespace std;
#include "mainclass.h"
#include "mysubobject1.h"
const string dataString[] =
{
"stringvalue,stringvalue,stringvalue,stringvalue,19,51,36,41,STUFF1",
"stringvalue,stringvalue,stringvalue,stringvalue,19,52,37,44,STUFF2",
"stringvalue,stringvalue,stringvalue,stringvalue,19,53,38,46,STUFF3",
"stringvalue,stringvalue,stringvalue,stringvalue,19,54,39,49,STUFF1",
"stringvalue,stringvalue,stringvalue,stringvalue,19,55,30,38,STUFF2",
};
MyObject* myObjectArray[5];
const string* dataArray[5];
int delimiterPositionArray[5][9];
string tokenArray[5][9];
Stuff stuff;
void main()
{
MainClass* mainClass = new MainClass();
dataArray[0] = &dataString[0];
dataArray[1] = &dataString[1];
dataArray[2] = &dataString[2];
dataArray[3] = &dataString[3];
dataArray[4] = &dataString[4];
/*Parse the contents of string into Token array. I have this working and can share if necessary but trimmed it out to keep this easy to look at */
for (int i = 0; i < 5; i++)
{
/* Logic to set the value of stuff goes here - it's very simple and trimmed for ease of reading */
mainClass->add(tokenArray[i][0], tokenArray[i][1], tokenArray[i][2], tokenArray[i][3], stoi(tokenArray[i][4]), stoi(tokenArray[i][5]), stoi(tokenArray[i][6]), stoi(tokenArray[i][7]), stuff);
}
cout << "TEST" << endl;
cout << mainClass->myObjectArray[0] << endl;
}
void MainClass::add(string string1, string string2, string string3, string string4, int int1, int int2, int int3, int int4, Stuff stuff)
{
MyObject myObject;
if (stuff == STUFF2) {
MySubObject1 myObject;
myObject.SetStuff(stuff);
}
myObject.SetString1(string1);
myObject.SetString2(string2);
myObject.SetString3(string3);
myObject.SetString4(string4);
myObject.SetInt1(int1);
int* intArray[] = { &int2, &int3, &int4 };
myObject.SetIntArray(intArray);
//Awful temporary array filling logic (which doent work properly, but works for the purpose of testing this problem)
if (myObjectArray[0] == nullptr)
{
myObjectArray[0] = &myObject;
}
else
{
if (myObjectArray[1] == nullptr)
{
myObjectArray[1] = &myObject;
}
/* ….until the array is filled */ }
}
And the question:
When I inspect this line of code from the main method in the mainclass.cpp in the VB debugger, all looks perfect. Token array contains what I expect:
mainClass->add(tokenArray[i][0], tokenArray[i][1], tokenArray[i][2], tokenArray[i][3], stoi(tokenArray[i][4]), stoi(tokenArray[i][5]), stoi(tokenArray[i][6]), stoi(tokenArray[i][7]), stuff);
I keep stepping through the code and get through the end of the add method. I see that everything looks fine by the time I reach the end of the add method. The strings and integers all appear to get set perfectly. I inspect the following line after the debugger runs over it and see everything looks great. Each array field has the data I expect in it. (the logic sucks and the data is the same for each array index, but that is for a later troubleshooting session :D)
myObjectArray[0] = &myObject;
After the add method runs, execution is deferred back to the main method and the following code outputs the results to the screen:
cout << "TEST" << endl;
cout << mainClass->myObjectArray[0] << endl;
This is where the problem is.... mainClass->myObjectArray[0] has empty values in all string properties and nothing is outputted for them (they contain "").... but the int properties have the proper output for some reason!
If anyone would have any insight into why the ints are available and the strings don't appear to be, I would be eternally grateful!
Thanks again!
Given you really didn't post all of your code, the code you did post shows one major issue, and could be the reason why your program behaves as it does.
In your MainClass::add() function, you're storing the addresses of local variables in the MainClass::myObjectArray array, and attempting to access these addresses from outside the add() function.
A synopsis of the code:
int main()
{
MainClass* mainClass = new MainClass();
//...
mainClass->add(...);
//...
cout << mainClass->myObjectArray[0] << endl; // <-- index 0 points to a garbage value
}
void MainClass::add(string string1, string string2, string string3, string string4, int int1, int int2, int int3, int int4, Stuff stuff)
{
MyObject myObject;
if (stuff == STUFF2) {
MySubObject1 myObject; // <-- Local variable
//...
int* intArray[] = { &int2, &int3, &int4 }; // <-- Another local variable
//...
myObject.SetIntArray(intArray); // <-- Storing address of local
//...
myObjectArray[0] = &myObject; // <-- Storing address of local
//...
}
When add() returns, those addresses will not be pointing to valid variables, since those variables no longer are valid since they are local variables.
So the fix is that you have to ensure that whatever pointers you place in your myObjectArray array, the lifetimes (scope) of those variables that are pointed to will last as long as myObjectArray.
A better solution to use an array of a type that stores "any" value such as an array of std::any.
In addition to this, you should attempt to reduce the unnecessary calls to new. For example, your main function starts off on the wrong foot:
int main()
{
MainClass* mainClass = new MainClass();
This could have simply been:
int main()
{
MainClass mainClass;

How to return a string in C++ [duplicate]

This question already has answers here:
Can a local variable's memory be accessed outside its scope?
(20 answers)
Closed 6 years ago.
#include <iostream>
#include<string.h>
using namespace std;
char *rt()
{
char a[20];
strcpy(a,"I am a beginner");
cout<<a;
return a;
}
int main()
{
char *a;
a=rt();
cout<<endl;
cout<<a;
return 0;
}
Here I have made a short program for understanding the same....I was expecting the output to be as
I am a beginner
I am a beginner
UPDATE:
But it turned out to be
I am a beginner
ëóG
I have read many articles and post but I am not able to understand their complex language....so I will appreciate a no-nonsense answer ( for a stupid...like me!!)
UPDATE:
Actually, there is one question in my assignment which goes like this
class COMPUTER
{
char chiptype[10];
int speed;
public:
void showdetails()
{
cout<<chiptype;
cout<<"\t"<<speed;
}
void getdetails()
{
cin.getline(chiptype,10);
cin>>speed;
}
};
Here the data has to be read and stored into a binary file....and the records having chiptype as "CD" are to be displayed.
Now my question is that...as the variable chiptype is private so I can't use it for comparison in main()....so I thought of making a function which returned the value stored in chiptype.
And I am not allowed to use std::string as well as node implementation...
char a[20]; is allocated on stack. When the function rt() returns, the stack unwinds and a goes out of scope. Hence you do not get your desired result.
While you are on C++, may I suggest using std::string
Read the comment below:
The other trick is to wrap the array in a struct, and return the
struct. Since a struct is copyable, the array internally becomes
copyable and will not lose scope. See this answer. Then you're not
dealing with pointers at all. See this live example – PaulMcKenzie
Use std::string instead of char[]
#include <iostream>
#include<string>
std::string rt()
{
std::string a("I am a beginner");
std::cout<<a;
return a;
}
int main()
{
std::string a;
a=rt();
std::cout<<std::endl;
std::cout<<a;
return 0;
}
In your original code char a[20] is allocated on the stack and return a; will return a pointer to a stack variable that is no longer valid when you receive it in you main() -- handling strings in c++ should generally be done using std::string as it handles all the nasty memory management that wil kill your program if you aren't careful.
If you have to use pointers and not use std::string, you would need to go the c style way with the risk of having memory leaks if you miss a step or two. The code would look something like this using c style (keeping the cout c++)
#include <iostream>
#include <strings.h>
std::string rt()
{
char *a = malloc(20); // allocate the memory on heap
strcpy(a,"I am a beginner");
std::cout<<a;
return a;
}
int main()
{
char *a;
a=rt();
std::cout<<std::endl;
std::cout<<a;
free(a); // release the memory
return 0;
}
Caution: I don't recommend that you do the above style -- in a real world application you will likely get into trouble by either forgetting to free the memory, or accidentally accessing the memory after it has been free'd
The problem is that the memory of a will be destroyed as soon as program returns from the function. I do not think you should work with dynamic memory at your level of knowledge, so I suggest you define the array outside and just modify it inside the function:
#include <iostream>
#include<string.h>
#define MAX_LENGTH 20
using namespace std;
void rt(char *a)
{
strcpy(a,"I am a beginner");
cout<<a;
}
int main()
{
char a[MAX_LENGTH];
rt(a);
cout<<endl;
cout<<a;
return 0;
}
Furthermore, you should take care that rt is not writing more than MAX_LENGTH characters.
As mentioned by other use std::string instead of char [].
std::string rt()
{
std:: string a = "I am a beginner"; // This statement is equivalent to std::string a("I am a beginner");
std::cout << a "\n";
return a;
}
Main reason of not getting the desired result is " char a[] is allocated on stack, but when function return stack become empty.
P.S : You need to include <string> in your program, to use std::string

Why I cannot receive a characters in C++

This is my code to receive string.
But I don't know what causes a problem.
Anybody knows?
#include<iostream>
#include<cstring>
using namespace std;
class person{
private:
char name[100];
//char * name;
public:
person(void) : name(){}
person(person& myPerson);
~person(void) {delete []name;}
void read();
void write();
};
person::person(person& myPerson ){
strcpy(name ,myPerson.name);
}
void person::read(){
cout<< "read name from console: " ;
cin >> name;
}
//////// <<---- problem point.
void person::write(){
cout << name << endl;
}
void main(void) {
person p1;
p1.read();
//p1.write();
getchar();
}
//I insert "getchar()" to remain console window for a while
Remove delete []name; from the destructor of person. You should only free memory that is heap allocated, with malloc() or new, and not space that is stack allocated, like your fixed-size array declared char name[100]. This change will fix the memory error you receive when the destructor is executed as the program exits.
Your code has a number of errors or bad style.
First, it's recommend to use C++ standard library facilities as much as possible. So use std::string instead of char[SIZE].
Second, use int main{return 0;} instead of void main{}.
Third, delete [] name; will lead to a memory error. You are freeing stack memory not heap memory.
Last, in my opinion, class names should start with a capital letter (Person).

SIGABRT in binary read/write

I wrote a very small code snippet and have already gotten the following error:
malloc: *** error for object 0x100100080: pointer being freed was not allocated
Problem is, I have no idea what pointer the compiler's talking about. I pass a variable in by address to the read/write functions, but I never freed it as far as I know. Where's the error in my code? I ran it with Leaks and Zombies, but got nothing.
Here's my program:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
class Bank
{
private:
string __name;
public:
Bank()
{
__name = "";
}
Bank(string name)
{
__name = name;
}
string getName() const { return __name; }
};
int main (int argc, char * const argv[])
{
Bank bank("Bank of America");
Bank bank2;
cout << "Bank1: " << bank.getName() << endl;
string filename = bank.getName() + ".bank";
ofstream fout(filename.c_str(), ios::binary);
if (fout.good())
fout.write((char *)&bank, sizeof(bank));
fout.close();
ifstream fin(filename.c_str(), ios::binary);
if (fin.good())
fin.read((char *)&bank2, sizeof(bank2));
fin.close();
cout << "Bank2: " << bank2.getName() << endl;
return 0;
}
You can't read an object that contains a std::string (or anything that's not Plain Ol' Data) with fin.read()--
The object is read and written as a stream of bytes, but std:string contains a pointer to memory that is stored elsewhere and is not written with your fout.write() and is not initialized properly with your fin.read()
It is because it is not initialized properly with your fin.read() that you are getting the heap error; when the object goes out of scope, the destructor of the improperly initialized std::string is being called, and trying to free memory that it doesn't own.
You probably want to write a custom i/o method for your object and save or load it piece-by-piece. For a shortcut to doing this, use the Boost serialization library.
Because your Bank class contains a std::string, you can't read/write it as binary like you are thinking. A std::string has internal pointers. If you write it as binary, you are just going to be writing pointers and not the actual string contents. Likewise, when you read the string, you are going to be reading a pointer. In this case, you end up making both your bank and bank2 objects have strings which point to the same memory, so when that memory is freed it gets freed twice.
You'll need to have some other way of writing your bank data to a file. In this case, a simple ASCII file with the bank name would be fine.
You cannot do what you are doing, simply because std::string cannot be copied like that. Internally a string object allocates memory and a simple copy of the outer structure doesn't do what you expect.
You need to serialize this structure properly.
Don't use underscores, please
Pass objects by reference: Bank(string& name), please
This is evil: fout.write((char *)&bank, sizeof(bank));
You may want to write << and >> ostream operators of your Bank class.
For example:
friend std::ostream& operator<<(std::ostream &out, const Bank& b);
friend std::istream& operator>>(std::istream &out, const Bank& b);
Members functions write of ostream and read of istream are specifically designed to input and output binary data. If you do want to manipulate binary data, use the following:
ifstream fin(filename.c_str(), ios::in|ios::binary|ios::ate);
size = fin.tellg();
memblock = new char [size];
fin.seekg(0, ios::beg);
if (fin.good()){
fin.read(memblock, size);
fin.close();
}
delete[] memblock;

Writing and reading objects with virtual methods to a binary file

Hi I'm currently working on a simulation program that tries to save the state (variables and objects) of the program to a binary file when requested so that it can resume the simulation if needed.
Just as a note: I know that this is not compatible across different CPU architectures and that is absolutely fine!
Everything seemed to be working fine until it came to writing an object that has virtual methods to a file and then trying to reading it back.
The following code illustrates this problem:
header.hpp
using namespace std;
class parent
{
public:
int mValue;
virtual string getName() =0;
virtual size_t getSize() =0;
parent(int value) : mValue(value)
{
}
};
class bob : public parent
{
public:
bob(int value) : parent(value)
{
}
string getName();
size_t getSize() { return sizeof(bob); }
};
string bob::getName()
{
string name("bob");
return name;
}
class sarah : public parent
{
public:
sarah(int value) : parent(value)
{
}
string getName();
size_t getSize() { return sizeof(sarah); }
};
string sarah::getName()
{
string name("sarah");
return name;
}
write.cpp
#include <iostream>
#include <fstream>
#include <string>
#include "header.hpp"
int main()
{
sarah girl(1);
bob boy(2);
parent* child1 = &girl;
parent* child2 = &boy;
cout << "Created child called " << child1->getName() << endl;
cout << "Created child called " << child2->getName() << endl;
//save sarah and bob to a binary file
ofstream file("temp.bin", ios::binary | ios::trunc);
if(!file.is_open())
return 1;
//format <size><data><size><data>....
size_t tempSize=0;
//write child1
tempSize = child1->getSize();
file.write( (char*) &tempSize,sizeof(size_t));
file.write( (char*) child1,tempSize);
tempSize = child2->getSize();
file.write( (char*) &tempSize,sizeof(size_t));
file.write( (char*) child2,tempSize);
file.close();
return 0;
}
read.cpp
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
#include "header.hpp"
int main()
{
//read sarah and bob from a binary file
ifstream file("temp.bin", ios::binary);
//format <size><data><size><data>....
size_t tempSize=0;
//get size of child1
file.read( (char*) &tempSize, sizeof(size_t));
//allocate memory for child1
parent* child1= (parent*) malloc(tempSize);
//read child 1 back
file.read( (char*) child1,tempSize);
//get size of child2
file.read( (char*) &tempSize, sizeof(size_t));
//allocate memory for child2
parent* child2= (parent*) malloc(tempSize);
//read child 2 back
file.read( (char*) child2,tempSize);
file.close();
//Using virtual methods causes SEGFAULT
cout << "Recreated child" << child1->getName() << endl;
cout << "Recreated child" << child2->getName() << endl;
return 0;
}
And building and running as follows:
g++ -g write.cpp -o write ; ./write
g++ -g read.cpp -o read ; ./read
When I step through the read program in gdb I've noticed the problem appears to be the v-table pointer. When I recreate "sarah" (child1) in the read program the v-table pointer is the one that existed for the write program, not the read program. So presumably this v-table pointer for "sarah" in the write program points to an invalid region of memory which is causing the SEGFAULT.
I have two questions:
Is it possible to save the v-table pointer information to the binary file in the "write" program so that my objects are perfectly recreated in the "right" program without resorting to a library such as Boost::Serialization or POST++ to handle this for me?
If it isn't possible ... or if it's quite complicated then I will have to add a constructor and a "saveState()" method (that can act on a ifstream and ofstream object respectively) so that each class (in this case sarah and bob) handles saving and reading it's state from a binary file. The problem with this is that I have multiple classes that are derived from the class "parent" so I would need a way for the "read" program to work out which constructor to call from reading the binary file.
I came up with one way of working out which constructor to call. This would be
Giving each class that derives from "parent" a unique ID
In the "write" program add unique ID to the binary file
In the "read" program read each unique ID and then use a switch statement to call the relevant constructor.
This isn't very elegant though as every time I add a new class that derives from "parent" I have to give it an ID and add it to the switch statement in "read". Is there a better way of doing it?
Thanks for reading, I know my post is long!
Every time your program gets compiled it puts functions in different places in memory. Also, on some operating system configurations, functions might even move around every time you restart the program. It's a security feature called address space layout randomization. If you know for sure that you will be reading and writing an object from the exact same binary, you might be able to do what you want by putting your read and write functions in the same program instead of two different ones. However, even this is fraught with the problem that if you make a change and recompile, you can no longer read your old data files anymore.
Boost::Serialization was created specifically to avoid all these issues, including I'm sure some I'm not even aware of, is heavily peer reviewed and tested, and has an extremely liberal license as a bonus. Use of such a library is not something to be "resorted" to, it's a privilege.