I am implementing a stack and I would like to push and pop string data. can I not just set
string name = originalString ???
here is what I have for push:
void push(StackNode** top_ref, int nAttack, int nDefense, string nName, string nType) {
StackNode* stackNode = (StackNode*)malloc(sizeof(StackNode));
stackNode->attack = nAttack;
stackNode->defense = nDefense;
stackNode->name = nName; //not working
stackNode->type = nType; //not working
stackNode->next = NULL;
stackNode->next = *top_ref;
*top_ref = stackNode;
}
where stackNode->name
and stackNode->type is already defind as a string
I keep getting: "Error reading characters of string."
The issue is malloc doesn't play well with objects. See Does malloc create a new instance of the class or not?
malloc allocates enough space to hold a StackNode, but doesn't call the constructor on it. Nor does it create the underlying member objects, your strings included. To do so, you need to do like described in this answer:
A* a = (A*)malloc(sizeof(A));
new (a) A();
a->~A();
free(a);
But at this point, you really should just be using new anyway. There's very little reason to use new in C++ (there's a time and a place, but minimize it). There's even fewer times when it's right to call malloc.
Do
StackNode* stackNode = new StackNode;
which will call the constructor appropriately. Remember to call delete on the memory when you're done with it!
Related
what's the difference between these two methods?
Method(CustomClass t)
{
CustomClass *temp = &t;
}
called like this
Method(CustomClass(1,2,3));
and
Method(CustomClass* t)
{
CustomClass *temp = t;
}
called like this
Method(new CustomClass(1,2,3));
i haven't coded in c++ for a few years now and am having some trouble remembering. I'm coming from c# where every class need to be dynamically allocated with 'new'. The thing is that i don't undertand the difference between alocating an object dynamically with 'new' and calling it normally. How does temp differ in the 2 examples?
More specific example: I was creating a linked list and for my list i had this method:
void List::AddNew(TestClass node)
{
if (!first)
{
first = &node;
}
else
{
bool setFirst = false;
if (!last)
setFirst = true;
TestClass *temp;
temp = last;
last = &node;
if (temp)
temp->next = last;
if (setFirst)
first->next = last;
}
}
where first and last are TestClass *; the list wasn't initialized correctly (first and last pointed to the same value) and i had no idea why, so i changed the method to this:
void List::AddNew(TestClass* node)
{
if (!first)
{
first = node;
}
else
{
bool setFirst = false;
if (!last)
setFirst = true;
TestClass *temp;
temp = last;
last = node;
if (temp)
temp->next = last;
if (setFirst)
first->next = last;
}
}
and now it works. I'm missing a basic principle for pointers and i can't seem to guess that it is.
Here is TestClass also:
class TestClass
{
public:
int x, y;
TestClass *next;
TestClass *prev;
TestClass();
TestClass(int,int);
~TestClass();
};
what's the difference between these two methods?
One of them is using stack (automatic) allocation, while the other is using heap (dynamic) allocation.
Method(CustomClass(1,2,3)); // stack based
Method(new CustomClass(1,2,3)); // heap based
If you're going to use new you need to make sure you delete that reference also. Otherwise, you'll have a memory leak.
yes, i know this but what's the real defference between the
allocations and when should i use one or the other?
Object lifetime. If you put something on the stack, you will only be able to use it within a particular function, and any functions below it will need it passed as a parameter. If you put it on the heap, you can return a reference to it and use it wherever you want. You can't return a reference / address to a stack variable since it's life ends when the function returns.
I think you're most confused about when to use dynamic-allocation vs when to use stack-allocation. The only thing to know is that you should use stack-based allocation when there is no need for dynamic-based allocation. When is dynamic- (or heap) allocation needed you ask? Well, normally you would use it when you need an object to exist beyond the scope in which it was created or when the contents of that dynamically-allocated object rely on a strictly runtime mechanism (like the addition of elements to a vector (the size may not be known at compile-time)). Also, this...
T* t = &t;
Is not heap-allocation. This is simply a pointer with automatic-storage duration (on the stack) pointing to another object on the stack (if t is itself stack-based). Allocation on the heap happens only when new is used.
CustomClass *temp;
temp is only a pointer. It points to NULL(ok, actually it can point everywhere, but you should set it to NULL if no object exists) or to a already existing class.
CustomClass tmp;
Creates a object.
Method(CustomClass* t):
Demands for a already existing Object (t = pointer to existing object).
CustomClass *temp = t;
Assigns the pointer to a new local pointer.
Method(CustomClass t):
Should create a copy of the class you pass (not sure...)
CustomClass *temp = &t;
& = Adress-Operator. Retrieves address of t and saves it to the local pointer temp.
mfg
So i have the following class
class Community
{
private:
char* Name;
char foundationDate[11];
Person* founder;
int maxMembersCount;
int membersCount;
Person* members;
static int communitiesCount;
.....
and i want to implement a copy constructor :
Community::Community(const Community& other)
{
this->Name = new char[strlen(other.Name)+1];
strcpy(this->Name,other.Name);
strcpy(this->foundationDate,other.foundationDate);
this->founder = other.founder;
this->maxMembersCount = other.maxMembersCount;
this->membersCount = other.membersCount;
this->members = new Person[this->maxMembersCount];
this->members = other.members;
communitiesCount++;
}
but this code crashes whenever i say Community A=B;
so for me this code seems legit, but when i start debugging there is the message: this-> "unable to read memory". Please help me if you need more code example please let me know.
Community::Community(const char* name , char foundDate[],Person* founder,int maxMembers) {
this->Name = new char[strlen(name)+1];
strcpy(this->Name,name);
strcpy(this->foundationDate,foundDate);
this->founder = new Person(founder->getName(),founder->getEGN(),founder->getAddress());
this->maxMembersCount = maxMembers;
this->membersCount = 2;
this->members = new Person[this->maxMembersCount];
communitiesCount++;
}
this is the main constructor of the class which works just fine....
There are multiple problems here, any of whichi could be part or all of the problem.
If Name or foundationDate is not null-terminated on the right-hand side, it will run off and copy bad memory.
If founder or members are owned by the object, you will either leak memory if you don't delete them in the destructor, or cause a whole variety of memory-related problems when you shallow-copy and then delete twice, etc.
To fix this, just make your Name and foundationDate std::string, and then make founder and members be owned by value rather than by pointer. If you absolutely have to allocate them on the heap use a smart pointer such as shared_ptr to hold it instead of a bug-prone raw pointer.
First of all, check that other.Name is filled with a pointer to a null-terminated string, that other.foundationDate contains a null-terminated string. That is, you pass good pointers to strlen and strcpy.
If that's true, check that B in the assignment is accessible altogether.
If that's true too, printf everything. And debug where exactly the exception occurs. Or post whole code that is compilable and which reproduces the error.
Also note that here:
this->members = new Person[this->maxMembersCount];
this->members = other.members;
the first assignment does nothing (leaks memory, in fact) while the second double deletes your memory upon object destruction (if you properly delete[] members).
My program crashes when I try to assign a string value to a member of a structure.
My suspicion is that the member (of type string) within the structure was never properly allocated in memory.
Here is my code for reference:
#include <string>
#include <sstream>
struct DataRow
{
std::string result;
float temp;
struct DataRow* next;
};
int main( )
{
DataRow* node = (DataRow*)malloc(sizeof(DataRow)); // Allocation of memory for struct here
int currentLoc = 0;
std::string dataLine = "HUUI 16:35:58 54.4 25.1 PDJ 1 MEME PPP PS$% sc3 BoomBoom SuperPower P0 123 25.86 0 11.1 1.0 50.0 W [2.0,0.28] 1.15 [5,6,100]";
std::string dataWord;
std::stringstream sDataLine( dataLine );
while ( sDataLine >> dataWord )
{
if( currentLoc == 0 )
{ node->result = dataWord; } // <-- Problem occurs here
else if ( currentLoc == 3 )
{ node->temp = atof(dataWord.c_str()); } // <-- This code works no problem on it's own
else
{ }
currentLoc++;
}
return 0;
}
The code fails at node->result = dataWord. But if I comment out this if statement, and leave only the node->temp=atof(dataWord.c_str()); the code works no problem.
How do I achieve proper memory allocation for the string member of the DataRow struct?
malloc doesn't ensure any constructors of the members of your struct are called. In C++ struct is basically the same as class, the only difference is that members are public by default rather than private. So you should new the object/struct, and delete it when done.
The way you are allocating node is incorrect: if you want to dynamically allocate non-POD types in C++, you need to use new, since it will call the required constructors (followed by a call to delete when appropriate).
But it might be simpler to allocate an automatic instance:
DataRow node;
If you do need a pointer, make sure to have a look at smart pointers, particularly std::unique_ptr and std::shared_ptr. See also boost::scoped_ptr.
In C++ use 'new' instead of 'malloc'. Using malloc does not run the constructor of your class, so the string is not initialized.
You have to create a new struct and not use malloc at all.
So use:
DataRow* node = new DataRow;
you should also take care of cleaning it up like so:
delete node;
and in case you don't want to allocate it from the heap you can do this as well:
DataRow node;
So before I get to answering your question I just wanted to say that you should not use Malloc in c++ unless you are forced to. This answer explains why fairly well.
In what cases do I use malloc vs new?
With that said changing this line
DataRow* node = (DataRow*)malloc(sizeof(DataRow));
To this
DataRow* node = new DataRow;
Will fix your problem
As someone who never dealt with freeing memory and so on, I got the task to create a dynamic array of struct and create functions to add or delete array elements. When deleting I have to free the memory which is no longer necessary.
when deleting the 2nd element of an array of the size of 3, I move the 3rd element to the 2nd position and then delete the last one. When deleting the last one, I always get an error... Is there anyone who can find an solution for me?
struct myFriend {
myFriend() {
number=0;
hobbys = new char*[10];
}
int number;
char* name;
char** hobbys;
};
int main() {
myFriend* friendList = new myFriend[10];
myFriend* tempFriend = new myFriend;
tempFriend->number=1;
tempFriend->name = "ABC";
myFriend* tempFriend2 = new myFriend;
tempFriend2->number=2;
tempFriend->name = "XYZ";
myFriend* tempFriend3 = new myFriend;
tempFriend3->number=3;
tempFriend3->name = "123";
friendList[0] = *tempFriend;
friendList[1] = *tempFriend2;
friendList[2] = *tempFriend3;
friendList[1] = friendList[2]; //move 3rd element on 2nd position
delete &(friendList[2]); //and delete 3rd element to free memory
}
Why did you create temporary variables? They're not even needed.
If you use std::vector and std::string, the problem you're facing will disappear automatically:
std::vector<myFriend> friendList(10);
friendList[0]->number=1;
friendList[0]->name = "ABC";
friendList[1]->number=2;
friendList[1]->name = "XYZ";
friendList[2]->number=3;
friendList[2]->name = "123";
To make it work, you should redefine your struct as:
struct myFriend {
int number;
std::string name;
std::vector<std::string> hobbys;
};
If you're asked to work with raw pointers, then you should be doing something like this:
struct Friend
{
int number;
char* name;
};
Friend * friends = new Friend[3];
friends[0]->number=1;
friends[0]->name = new char[4];
strcpy(friends[0]->name, "ABC");
//similarly for other : friends[1] and friends[2]
//this is how you should be deleting the allocated memory.
delete [] friends[0]->name;
delete [] friends[1]->name;
delete [] friends[2]->name;
delete [] friends; //and finally this!
And if you do any of the following, it would be wrong, and would invoke undefined behavior:
delete friends[2]; //wrong
delete &(friends[2]); //wrong
It is impossible to delete a subset from array allocated by new []
myFriend* friendList = new myFriend[10];
You have a single whole array
+------------------------------------------------------------------+
| friendList[0] | friendList[1] | ..... | friendList[9] |
+------------------------------------------------------------------+
You can not delete &(friendList[2]).
You get from C++ whole array of 10 elements.
This array starts from friendList (or &(friendList[0])).
operator delete with pointer to the address returned by new (i.e. friendList) is valid
only.
Two things I noticed. (1) You are apparently supposed to "create functions to add or delete elements" but you haven't done that, you have only created one function. (2) You are making your work harder than it needs to be by using a struct that also needs to manage memory. I suggest you use a simpler struct.
Your assignment is, in effect, to make a simple 'vector' class, so I suggest that you do that. Start with a struct that is empty. If the teacher requires you to use the myFriend struct as written, you can add that in after you finish making your vector like functions. I'm going to assume that you aren't allowed to make a class yet because most instructors make the mistake of leaving that until last.
struct MyStruct {
int value; // start with just one value here. Dealing with pointers is more advanced.
};
MyStruct* array;
int size;
int capacity;
void addMyStruct(MyStruct& value); // adds a MyStruct object to the end.
void removeMyStructAtPosition(int position); // removes the MyStruct object that is at 'position'
// I leave the functions for you to implement, it's your homework after all, but I give some clues below.
void addMyStruct(MyStruct& value) {
// First check that there is enough capacity in your array to hold the new value.
// If not, then make a bigger array, and copy all the contents of the old array to the new one.
// (The first time through, you will also have to create the array.)
// Next assign the new value to array[size]; and increment size
}
void removeMyStructAtPosition(int position) {
// If the position is at end (size - 1,) then simply decrement size.
// Otherwise you have to push all the structs one to the left (array[i] = array[i + 1])
// from position to the end of the array.
}
int main() {
// test your new class here.
// don't forget to delete or delete [] any memory that you newed.
}
The array size is fixed at 10, so you don't need to delete any elements from it. But you do need to delete the name and hobbys elements of friendList[1] (and before you overwrite it). There are two problems here:
You are setting friendList[0]->name = "ABC"; Here, "ABC" is a constant zero-terminated string somewhere in memory. You are not allowed to delete it. So you have to make a copy.
You want to delete hobby[i] whenever it was assigned. But in your code, you can't tell whether it was assigned. So you have to set every element to 0 in the constructor, so that you will later know which elements to delete.
The proper place to delete these elements is in myFriends's destructor.
It seems the point of the question is to manage a dynamic array. The main problem is that he is using an array of friendList. Use an array of pointers to friendList:
struct myFriend {
myFriend() {
number=0;
hobbys = new char*[10];
}
int number;
char* name;
char** hobbys;
};
int main() {
myFriend** friendList = new myFriend*[10];
myFriend* tempFriend = new myFriend;
tempFriend->number=1;
tempFriend->name = "ABC";
myFriend* tempFriend2 = new myFriend;
tempFriend2->number=2;
tempFriend->name = "XYZ";
myFriend* tempFriend3 = new myFriend;
tempFriend3->number=3;
tempFriend3->name = "123";
friendList[0] = tempFriend;
friendList[1] = tempFriend2;
friendList[2] = tempFriend3;
friendList[1] = friendList[2]; //move 3rd element on 2nd position
delete friendList[2]; //and delete 3rd element to free memory
}
But everybody else is right -- there are major issues around memory allocation for both 'hobbys' and for 'name' that you need to sort out separately.
To do your homework I'd suggest to learn much more about pointers, new/delete operators, new[]/delete[] operators (not to be confused with new/delete operators) and objects creation/copying/constructors/destructors. It is basic C++ features and your task is all about this.
To point some directions:
1) When you dynamically allocate the object like this
MyType* p = new MyType;
or
MyType* p = new MyType(constructor_parameters);
you get the pointer p to the created object (new allocates memory for a single object of type MyType and calls the constructor of that object).
After your work with that object is finished you have to call
delete p;
delete calls the destructor of the object and then frees memory. If you don't call delete your memory is leaked. If you call it more than once the behavior is undefined (likely heap corruption that may lead to program crash - sometimes at very strange moment).
2) When you dynamically allocate array like this
MyType* p = new MyType[n];
you get the pointer p to the array of n created object located sequentially in memory (new[] allocates single block of memory for n objects of type MyType and calls default constructors for every object).
You cannot change the number of elements in this dynamic array. You can only delete it.
After your work with that array is finished you have to call
delete[] p; // not "delete p;"
delete[] calls the destructor of every object in the array and then frees memory. If you don't call delete[] your memory is leaked. If you call it more than once the behavior is undefined (likely program crash). If you call delete instead of delete[] the behavior is undefined (likely destructor called only for the first object and then attempt to free memory block - but could be anything).
3) When you assign the struct/class then operator= is called. If you have no operator= explicitly defined for your struct/class then implicit operator= is generated (it performs assignment of every non-static member of your struct/class).
Here is the program...
class CopyCon
{
public:
char *name;
CopyCon()
{
name = new char;
}
CopyCon(const CopyCon &objCopyCon)
{
name = new char;
_tcscpy(name,objCopyCon.name);
}
~CopyCon()
{
if( name != NULL )
{
delete name;
name = NULL;
}
}
};
int main()
{
CopyCon objCopyCon1;
objCopyCon1.name = "Hai";
CopyCon objCopyCon2(objCopyCon1);
objCopyCon1.name = "Hello";
cout<<objCopyCon2.name<<endl;
return 0;
}
Once the code execution completes, when the destructor called, it crashes on 'delete' saying...
Debug Error!
Program: ...
HEAP CORRUPTION DETECTED: after Normal block (#124) at 0x00366990.
CRT detected that the application wrote to memory after end of heap buffer.
(Press Retry to debug the application)
Don't we have to clear the heap memory in destructor. What's wrong with this program? Pls someone help!
Copy constructor works perfectly as intended. But still... !?
The problem is you are allocating only one char in the copy constructor.
In main you are assigning a 4-byte string (remember the null), but when you copy the object, you only allocate enough room for 1 byte.
What you probably want to do is change
name = new char;
to
name = new char[tcslen(objCopyCon.name) + 1];
And in the destructor:
delete name;
to
delete [] name;
Also:
You are assigning "Hai" and "Hello" to objCopyCon1.name which is hiding the memory allocated in the constructor. This memory can never be freed!
You write past the allocated variable and that is undefined behavior.
When the folloing lines run
CopyCon objCopyCon1;
objCopyCon1.name = "Hai";
CopyCon objCopyCon2(objCopyCon1);
_tcscpy() copies 4 characters (3 letters and the null terminator) into a buffer that can legally hold only one character. So you write past the buffer end and this leads to heap corruption.
You need to alocate the buffer of the right size:
CopyCon(const CopyCon &objCopyCon)
{
name = new char[_tcslen(objCopyCon.name) +1];
_tcscpy(name,objCopyCon.name);
}
also you need to change the delete in the destructor to delete[] and also change all other new calls to new[] to avoid undefined behavior.
You are allocating one character and trying copy multiple characters into that memory location. First find out the length of the string then allocate length + 1 characters (extra char to accommodate the NULL character) using new char[length+1] syntax. You need to correspondingly change your destructor to delete[] name.
Besides the new char issue that everyone mentioned, the strings "Hai" and "Hello" reside in read-only memory. This means you cannot delete them (but you do so in your destructor) - this does generate crashes. Your code should not assign to name directly, but use a set function such as:
void set_name(const char *new_name)
{
delete [] name; // delete is a no-op on a NULL pointer
name = new char[tcslen(new_name) + 1];
_tcscpy(name,new_name);
}
I'm surprised that assignment does not produce a compiler warning to be honest. You are assigning a const char * to a char *, which can lead to all sorts of problems like the one you're seeing.
The job of the copy ctor should be to create a copy of the object. So the char array pointed to by name in the both the objects should be of the same size and same content, which is not happening in your case. So change
name = new char; // allocates only one char
to
name = new char[strlen(objCopyCon.name) + 1]; // allocate array of char
You need to allocate enough memory to hold the information you are trying to store. "Hai" is 4 bytes or chars (including the null terminator) and you have only allocated one. You also do not copy strings from one memory location to another using "=". You need to strncpy the string across.
Use std::string it will make your life a million times easier :)
Here the code that works perfect!
class CopyCon
{
public:
char *name;
CopyCon()
{
name = NULL;
}
CopyCon(const CopyCon &objCopyCon)
{
name = new char[_tcslen(objCopyCon.name)+1];
_tcscpy(name,objCopyCon.name);
}
~CopyCon()
{
if( name != NULL )
{
delete[] name;
name = NULL;
}
}
void set_name(const char *new_name)
{
//delete [] name; // delete is a no-op on a NULL pointer
if( NULL != name)
{
delete[] name; name = NULL;
}
name = new char[_tcslen(new_name) + 1];
_tcscpy(name,new_name);
}
};
int main()
{
CopyCon objCopyCon1;
objCopyCon1.set_name("Hai");
CopyCon objCopyCon2(objCopyCon1);
objCopyCon1.set_name("Hello");
cout<<objCopyCon1.name<<endl;
cout<<objCopyCon2.name<<endl;
return 0;
}
Thanks to all for their view points. It really helped!