C++ passing a pointer to static function changes value during execution - c++

Here is my code
Node* Node::createNode(int n)
{
Node newNode(n);
Node *temp = &newNode;
return temp;
}
void Node::printNode(Node* node)
{
cout << node->data << "\t" << node->next << endl;
system("pause");
}
Here is the main function
int main(int argc, char* argv[])
{
Node *head = Node::createNode(10);
Node::printNode(head);
return 0;
}
Problem, I was expecting to print 10. Instead I get a garbage value of -858993460. I have noticed that until the point, parameter is passed into the function, it retains correct value. But inside the function printNode, the value changes. So I guess something is going wrong in the function call. Any help would be appreciated.

You're returning a pointer to a local variable. When you later use that pointer in the main function, the variable it pointed to is long gone and you enter the realm of undefined behavior.
You could just return the node by value:
Node Node::createNode(int n)
{
Node newNode(n);
return newNode;
}
Or you could allocate one dynamically and return a smart pointer to it, enabling scope bound resource management (aka RAII):
std::unique_ptr<Node> Node::createNode(int n)
{
return std::unique_ptr<Node>(new Node(n));
}

You are returning a pointer to a locally scoped Node in createNode. This is a bad thing(tm). When that function goes out of scope (i.e. returns), who knows what happens to what you are pointing to.
instead use one of the following:
copy construct (and return by value)
allocate on heap (new Node) and return (pref. using smart pointers)

You're mistaken in the way you create the node:
Node* Node::createNode(int n)
{
Node newNode(n); // create a node on stack
Node *temp = &newNode; // get address of the node on stack
return temp; // return that address
} // and here the node is destructed!
You should have allocated it in the heap via operator new().
See also Stack, Static, and Heap in C++ and http://www.learncpp.com/cpp-tutorial/79-the-stack-and-the-heap/ for explainations.

You are returning a reference to a local
Node newNode(n);
Node *temp = &newNode;
return temp;
newNode goes out of scope and is overwritten by later stack contents.

In Node::createNode() function, you are returning the address of a local variable. This is a major gaffe. The life of the Node object goes out of scope once you return from the function, it gets ejected from the stack.

Related

Do pointers die after function ends?

void add_first(int e) {
        Node* newest = new Node(e, first);
        first = newest;
        n++;
}
On this code i declared a node pointer "newest".
list->add_first(4);
Let's say i call that function for the second time.
list->add_first(8)
Is it still that same *newest from the first time i called the function pointing at a new node OR did the previous *newest die after the function and on the second function call a new *newest was generated?
//Full code in case you need extra information
template <typename T>
class List {
struct Node {
T elem;
Node* next;
Node(T elem = 0, Node* next = nullptr) : elem(elem), next(next) {}
};
Node* first;
size_t n;
public:
List () : n(0), first(nullptr) {}
~List () {
while (first != nullptr) {
Node* aux = first;
first = first->next;
delete aux;
}
}
bool addFirst(T e) {
Node* newest = new Node(e, first);
first = newest;
n++;
return true;
}
bool add(T e, size_t p) {
if (p > n) return false;
if (p == 0) return addFirst(e);
Node* newest = new Node(e);
Node* aux = first;
size_t i = 1;
while (i++ < p) {
aux = aux->next;
}
newest->next = aux->next;
aux->next = newest;
n++;
return true;
}
bool addLast(T e) {
return add(e, n);
}
};
new Node(e, first)
will allocate new memory on the heap for an object of type Node, where it will remain until you manually deallocate it using delete. If you don't retain a reference to it, then you can't deallocate it and you have a memory leak.
Node* newest = ...;
will create a pointer of type Node on the stack until it goes out of scope (in this case, when the function returns), initializing it to reference the object you just created.
It's important to note that newest is not the object; it is merely referencing it for the time being.
first = newest;
The type of first is not provided here, but presumably in order for it to compile it is defined at a higher scope, e.g. a member variable, and accepts an assignment of type Node*...so it's probably a Node* itself.
In which case this will by default set first to reference the same object pointed to by newest. It is not pointing to newest in this scenario, but both are now referencing the same object.
When the function returns, newest(the pointer) will be destroyed because it is defined within the scope of the function invocation, but the Node object you created will live on the heap, as well as first which references it because it's defined outside this scope.
If you immediately call this function again, e.g. in a loop, you will allocate another object of type Node, set first to that object, and the object previously pointed to by first is now orphaned on the heap without a reference.
EDIT: I did just notice that you pass first into the constructor for Node, so it's possible you're making a separate connection therein.
newest (i.e. the pointer) dies when the function returns (because it is a local variable). The next time the function is called, a new newest variable is created and destroyed again.
*newest (i.e. the object it's pointing to) remains alive until you explicitly delete it (because you created it with new)
Pointers are just types which hold a memory address of an instance of a specific type. In your example you dynamically allocate memory to store an instance of Node using new and you store its address to a pointer (notice that new returns with a pointer which points to the allocated memory). When the function returns, the pointer "dies", but the allocated memory remains allocated.

c++ - delete dynamic memory allocation from function but unable to reach the variable

I have a dynamic memory allocation of List. How can I erase this memory when the program ends?
Outside the function I do not have access to newList and if I erase it in function and delete the newList before I return, then basically I return nothing.
Is newList deleted automatically when the program terminates or do I need to manually delete it?
main.cpp:
//reverse the list, return new list
List* reverseList(List &listToReverse) {
//dynamic memory allocation
List* newList = new List;
//pointer to first node
Node* currentPtr = listToReverse.getFirstNode();
while (currentPtr != 0) {
newList->AddElement(currentPtr->getdata());
currentPtr = currentPtr->getNextPtr();
}
Node* currentNode = newList->getFirstNode();
int size = newList->size();
while (currentNode != 0) {
currentNode->setId(size);
size--;
currentNode = currentNode->getNextPtr();
}
return newList;
}
int main() {
List l1;
cout << "The reversed list: " << endl;
reverseList(l1)->print();
system("pause");
return 0;
}
To fix you issue, you have a couple of solution:
store the pointer in a variable (in the main) and delete it (not the best solution)
return an automatic variable (not a pointer), the destructor will be called when the variable go out of scope (beware of shallow copy issues*) (check out move semantic)
use smart pointer
With modern OS, the memory will be cleaned after your program terminates BUT this is not a solution ! Always clean up every resources you have used !
* If you make a shallow copy and your type have (raw) pointers, the pointer inside the copy will point to the same object as the original. Which means that once the original delete his memory, the pointers in the copy will point to invalid memory.

Pointers and reference issue

I'm creating something similar to structure list. At the beginning of main I declare a null pointer. Then I call insert() function a couple of times, passing reference to that pointer, to add new elements.
However, something seems to be wrong. I can't display the list's element, std::cout just breaks the program, even though it compiler without a warning.
#include <iostream>
struct node {
node *p, *left, *right;
int key;
};
void insert(node *&root, const int key)
{
node newElement = {};
newElement.key = key;
node *y = NULL;
std::cout << root->key; // this line
while(root)
{
if(key == root->key) exit(EXIT_FAILURE);
y = root;
root = (key < root->key) ? root->left : root->right;
}
newElement.p = y;
if(!y) root = &newElement;
else if(key < y->key) y->left = &newElement;
else y->right = &newElement;
}
int main()
{
node *root = NULL;
insert(root, 5);
std::cout << root->key; // works perfectly if I delete cout in insert()
insert(root, 2);
std::cout << root->key; // program breaks before this line
return 0;
}
As you can see, I create new structure element in insert function and save it inside the root pointer. In the first call, while loop isn't even initiated so it works, and I'm able to display root's element in the main function.
But in the second call, while loop already works, and I get the problem I described.
There's something wrong with root->key syntax because it doesn't work even if I place this in the first call.
What's wrong, and what's the reason?
Also, I've always seen inserting new list's elements through pointers like this:
node newElement = new node();
newElement->key = 5;
root->next = newElement;
Is this code equal to:
node newElement = {};
newElement.key = 5;
root->next = &newElement;
? It would be a bit cleaner, and there wouldn't be need to delete memory.
The problem is because you are passing a pointer to a local variable out of a function. Dereferencing such pointers is undefined behavior. You should allocate newElement with new.
This code
node newElement = {};
creates a local variable newElement. Once the function is over, the scope of newElement ends, and its memory gets destroyed. However, you are passing the pointer to that destroyed memory to outside the function. All references to that memory become invalid as soon as the function exits.
This code, on the other hand
node *newElement = new node(); // Don't forget the asterisk
allocates an object on free store. Such objects remain available until you delete them explicitly. That's why you can use them after the function creating them has exited. Of course since newElement is a pointer, you need to use -> to access its members.
The key thing you need to learn here is the difference between stack allocated objects and heap allocated objects. In your insert function your node newElement = {} is stack allocated, which means that its life time is determined by the enclosing scope. In this case that means that when the function exits your object is destroyed. That's not what you want. You want the root of your tree to stored in your node *root pointer. To do that you need to allocate memory from the heap. In C++ that is normally done with the new operator. That allows you to pass the pointer from one function to another without having its life time determined by the scope that it's in. This also means you need to be careful about managing the life time of heap allocated objects.
Well you have got one problem with your Also comment. The second may be cleaner but it is wrong. You have to new memory and delete it. Otherwise you end up with pointers to objects which no longer exist. That's exactly the problem that new solves.
Another problem
void insert(node *&root, const int key)
{
node newElement = {};
newElement.key = key;
node *y = NULL;
std::cout << root->key; // this line
On the first insert root is still NULL, so this code will crash the program.
It's already been explained that you would have to allocate objects dynamically (with new), however doing so is fraught with perils (memory leaks).
There are two (simple) solutions:
Have an ownership scheme.
Use an arena to put your nodes, and keep references to them.
1 Ownership scheme
In C and C++, there are two forms of obtaining memory where to store an object: automatic storage and dynamic storage. Automatic is what you use when you declare a variable within your function, for example, however such objects only live for the duration of the function (and thus you have issues when using them afterward because the memory is probably overwritten by something else). Therefore you often must use dynamic memory allocation.
The issue with dynamic memory allocation is that you have to explicitly give it back to the system, lest it leaks. In C this is pretty difficult and requires rigor. In C++ though it's made easier by the use of smart pointers. So let's use those!
struct Node {
Node(Node* p, int k): parent(p), key(k) {}
Node* parent;
std::unique_ptr<Node> left, right;
int key;
};
// Note: I added a *constructor* to the type to initialize `parent` and `key`
// without proper initialization they would have some garbage value.
Note the different declaration of parent and left ? A parent owns its children (unique_ptr) whereas a child just refers to its parent.
void insert(std::unique_ptr<Node>& root, const int key)
{
if (root.get() == nullptr) {
root.reset(new Node{nullptr, key});
return;
}
Node* parent = root.get();
Node* y = nullptr;
while(parent)
{
if(key == parent->key) exit(EXIT_FAILURE);
y = parent;
parent = (key < parent->key) ? parent->left.get() : parent->right.get();
}
if (key < y->key) { y->left.reset(new Node{y, key}); }
else { y->right.reset(new Node{y, key}); }
}
In case you don't know what unique_ptr is, the get() it just contains an object allocated with new and the get() method returns a pointer to that object. You can also reset its content (in which case it properly disposes of the object it already contained, if any).
I would note I am not too sure about your algorithm, but hey, it's yours :)
2 Arena
If this dealing with memory got your head all mushy, that's pretty normal at first, and that's why sometimes arenas might be easier to use. The idea of using an arena is pretty general; instead of bothering with memory ownership on a piece by piece basis you use "something" to hold onto the memory and then only manipulate references (or pointers) to the pieces. You just have to keep in mind that those references/pointers are only ever alive as long as the arena is.
struct Node {
Node(): parent(nullptr), left(nullptr), right(nullptr), key(0) {}
Node* parent;
Node* left;
Node* right;
int key;
};
void insert(std::list<Node>& arena, Node *&root, const int key)
{
arena.push_back(Node{}); // add a new node
Node& newElement = arena.back(); // get a reference to it.
newElement.key = key;
Node *y = NULL;
while(root)
{
if(key == root->key) exit(EXIT_FAILURE);
y = root;
root = (key < root->key) ? root->left : root->right;
}
newElement.p = y;
if(!y) root = &newElement;
else if(key < y->key) y->left = &newElement;
else y->right = &newElement;
}
Just remember two things:
as soon as your arena dies, all your references/pointers are pointing into the ether, and bad things happen should you try to use them
if you ever only push things into the arena, it'll grow until it consumes all available memory and your program crashes; at some point you need cleanup!

how to make a function return a structure pointer in c++

I want to make the function return the address of a particular node .but the compiler is
not detecting the node datatype structure i created.
struct node
{
int data;
node *link;
};
node *header,*current;
node traverse(int pos);
node *Linkedlist::traverse(int pos)
{
int location = 0;
current->link = header->link;
node *address = new node;
address->data = NULL;
address->link = NULL;
while(current->link != NULL)
{
if(location == pos)
{
cout <<current->link->data <<" "<< endl;
address->link=current->link;
}
location ++;
current->link = current->link->link;
}
return address->link;
}
Change
return *address;
to
return address;
As address is a pointer variable to node, you need to simply return the variable.
A * preceding a pointer variable is an explicit referencing, which means to get the value pointed by the pointer variable address. This is antagonistic to what the operator & would have done, fetch the address of a variable.
return address;
So its logical that you should return the variable instead of returning the value pointed by the variable.
Note, care needs to be taken by the caller of traverse to free the memory explicitly by calling delete else this would result in memory leak. This is because of a potential design issue, where you have allocated a heap object inside a local scope and returned the address.
node * foo = Linkedlist::traverse(n);
...............
delete foo;
You could have simply created the object in the heap or add it as a class member, where in the former case, you can easily transfer the ownership of the object from one scope to another, where in the second case, the lifetime of the object would have been controlled by the object Linkedlist

C++ function using reference as param error

struct node {
string info;
node *next;
node() {
info = "string";
next = NULL;
}
};
void insert(node &anode) {
node newNode;
anode.next = &newNode;
}
What is wrong with this implementation of insert for this structure ? How should I fix this?
added: Very sorry that I wasn't clear. I know what is wrong with the program. I want to know how I can insert a new node to a reference node. Since I am using a reference to a node as a param this mean that node must not be a pointer? So its stored on stack? which means I can't use memory from heap? (or else seg fault?) so how am I suppose to use new ? This is my main confusion. Perhaps my approach is wrong but I don't see why it should be.
What's wrong is that newNode lives in the scope of the insert function. You probably want something like
void insert(node &anode) {
node* newNode = new node;
anode.next = newNode;
}
but the parent node, or something else, then has to take care of the new node's lifetime. It now owns the next node. If you want the caller to be in charge, then this might be more suitable:
void insert(node& parentNode, node& nextNode) {
parentNode.next = &nextNode;
}
Note that you can avoid some of the lifetime issues by using boost::shared_ptr or std::shared_ptr if you have access to C++0x. These smart pointers basically wrap a pointer and take care to delete it when nobody is using it. The code would look something like this:
struct node {
// other data members...
shared_ptr<node> next;
// constructors/destructors
};
void insert(node& anode) {
anode.next = shared_ptr<node>(new node);
}
Now you don't have to worry about deleting the new node at any point.
You're returning (implicitly, as member of anode) a pointer to the local variable newNode. newNode is destroyed when you're leaving insert, so anode.next contains an invalid pointer afterwards.
BTW: should this question be tagged "homework"? :)
The "what's wrong" has nothing to do with references.
This implementation stores a pointer to a local variable in anode.next. Local variable gets destroyed immediately afterwards (when insert function exists), while the pointer continues to live pointing into a destroyed location.
The problem is that the local variable newNode will go out of scope once the function insert exists, and anode.next will now reference an invalid node.
Assuming that you are talking about a runtime error. The problem is that in your insert function
node newNode
is only a local variable, and it will be causing a problem when you try to access it later while iterating on the node(s).
Inside the insert function you should be doing something like this:
node* newNode = new node();
anode.next = newNode;
If you insist on using free functions, your best bet is probably something like:
static node* head = NULL;
static node* current = NULL;
void insert(std::string& val)
{
if (!head) {
current = new node(val);
head = current;
} else {
current->next = new node(val);
current = current->next;
}
}
and having your constructor accept an std::string as an argument. Relying on an entity outside the function to create nodes for you is probably not the best idea. You can pseudo-encapsulate that by creating nodes on demand when you call insert. Then you can run through the nodes using the head pointer and consequently delete them when you're finished with the list.
You are using a static address.
void insert(node &anode) {
node newNode;
anode.next = &newNode;
}
newNode is a local object. At the end of the function, it will go out of scope and its address will be invalid.