Using pointers with recursion - c++

I want to have a node that will be able to point to another node through the function insert. However, I've messed up somehow so that the pointer p does not point to the next Node. I'm unsure of how to use my function in a way such that it will point to the recurred variable a.
This issue is occurring on a AVL tree assignment I've been working on. I've recreated the error in a simpler fashion in the below code.
#include <iostream>
using namespace std;
struct Node {
int data;
Node *next = NULL;
};
Node* insert(Node *a) {
cout << "inserter" << endl;
if (a != NULL) {
a->next = insert(a->next);
}
else {
cout << "inserting" << endl;
Node *a = new Node;
a->data = 10;
a->next = NULL;
}
return a;
}
int main() {
Node *p = new Node;
p->data = 5;
insert(p);
cout << "please" << endl;
cout << p->data << endl;
cout << p->next << endl;
cout << p->next->data << endl;
cout << "done" << endl;
return 0;
}
The output is:
inserter
inserter
inserting
please
5
000000
And then it crashes, as p->next is not pointing to anything. I don't know how I can get it to point to the recurrsed pointer a.
My main objective is to have a->next be changed without using a returning function, instead a void function that can change a->next using an & in the pass by reference. But I'm unsure how to incorporate the & into a pointer. This hasn't been working (Node *&a).

Your main reason for p->next being null is that the pointer you want to return is out of scope when you return it.
Outside of else {}, the new pointer you created is no longer valid.
else {
cout << "inserting" << endl;
a = new Node;
a->data = 10;
a->next = NULL;
}
Because of the Node* before a in your code, you are declaring a new Node pointer, instead of using the one that was passed to the function.

In your code, it doesn't seem like you are implementing a tree. It seems more like you are implementing a linked list.
Whatever. In the way you are doing, you can never track the starting node. You have to save it for traversing the tree/linked list.
struct node
{
int data;
node *next;
};
node *head, *tail;
void createnode(int value)
{
node *temp=new node;
temp->data=value;
temp->next=NULL;
if(head==NULL)
{
head=temp;
tail=temp;
temp=NULL;
}
else
{
tail->next=temp;
tail=temp;
}
}

Related

I have written a code for creating a linked list. While printing the list items I am getting SIGSEV error. How do we fix it?

I know I have done a silly mistake and to not make it again in the future I want to know why this error is showing up in the following code. I have already read on the internet that it is caused when our program is trying to access memory block which is not yet created but I cannot find where it is occurring in my program.
Thank You, Guys.
struct node
{
int value;
struct node *next;
};
typedef struct node Node;
Node *createNewNode(int value)
{
Node *result = new Node;
result->value = value;
result->next = NULL;
return result;
}
Node *insertHeadNode(Node **head, Node *nodeToInsert)
{
nodeToInsert->next = *head;
*head = nodeToInsert;
return nodeToInsert;
}
void print_list(Node *head)
{
Node *temp = head;
while (temp != NULL)
{
cout << temp->value << "->";
temp = temp->next;
}
cout << endl;
}
int main()
{
int value, i;
Node *head;
Node *tmp;
while (i < 5)
{
cout << "Enter the value of the linked list: ";
cin >> value;
tmp = createNewNode(value);
insertHeadNode(&head, tmp);
i++;
}
print_list(head);
return 0;
}
One more thing. I have dynamically created a struct in the createNewNode function. So we do delete it at the end of our program, right?
You have multiple parts in your code that result in undefined behavior.
You never initialize i so doing i < 5 isn't valid.
You never initialize Node *head so that one also holds an indeterminate value, that value is assigned to nodeToInsert->next in insertHeadNode.
So also cout << temp->value << "->"; would be invalid, at the point when temp = temp->next has reaced the node for which you assinged that indeterminate to next.

Unexpected return value from main() function

I am working with doubly linked list. Every function operates well but at the end of main(), it stalls few seconds and return an unexpected random value.
At first I thought it was caused by the report() function, thus I put one more add() function at the end but nothing got fixed. I doubt it is a memory deallocating problem, but I don't see where some object got pre-deallocated.
(Compiled using Code::Blocks 17.12).
Here is my .cpp file (all in one):
#include <iostream>
using namespace std;
typedef struct element {
element(){
data = 0;
next = 0;
prev = 0;
}
~element(){
delete next;
delete prev;
cout << "element destructed" << endl;
}
int data;
element* next;
element* prev;
} elem;
typedef struct doublylinkedlist{
doublylinkedlist(){
head = 0; tail = 0;
}
~doublylinkedlist(){
while(head!=0) {
head = head->next;
delete head->prev;
}
delete tail;
cout << "list destructed" << endl;
}
elem* head;
elem* tail;
} doublyll;
doublyll ls;
void add(){
elem* temp = new elem;
cout << "Enter an integer: ";
cin >> temp->data;
if(ls.head == 0) {//empty
ls.head = new elem;
ls.head = temp;
} else{
if(ls.tail == 0){ //1-item list
ls.tail = new elem;
ls.tail = temp;
ls.head->next = ls.tail;
ls.tail->prev = ls.head;
}
else{
temp->prev = ls.tail;
ls.tail->next = temp;
ls.tail = temp;
}
}
}
void report(){
if(ls.head == 0) cout << "List is empty!" << endl;
else{
elem *temp = ls.head;
do{
cout << temp->data << endl;
temp = temp->next;
} while (temp != 0);
}
}
int main(){
report();
add();
add();
add();
report();
add();
return 0;
}
Could someone point out where the error comes from and how to fix it? I want the main() not to stall and return 0 as usual, not to the opposite.
This is the program when executed, this is my build message
First point: The elements will be deallocated by the class doublylinkedlist, so deallocating elements in the class element will cause double-deallocation.
Therefore, you should remove two delete statements from the destructior of the lass element.
~element(){
/* remove them */
//delete next;
//delete prev;
cout << "element destructed" << endl;
}
Second point: In the destructor of doublylinkedlist, head->prev is read after head = head->next; without checking if head is NULL.
head can be NULL by the assignment, so it should be checked.
~doublylinkedlist(){
while(head!=0) {
head = head->next;
if (head!=0) /* add this */
delete head->prev;
}
delete tail;
cout << "list destructed" << endl;
}
The last element will be deallocated by delete tail;, so this code looks tricky but should be OK.
Extra point: These code segments
ls.head = new elem;
ls.head = temp;
and
ls.tail = new elem;
ls.tail = temp;
are causing memory leaks by allocating elements and throwing them right away.
You should remove the extra allocations.
/* remove this */
//ls.head = new elem;
ls.head = temp;
and
/* remove this */
//ls.tail = new elem;
ls.tail = temp;
Unless you are using std::shared_ptr or similar constructs each object needs to have one other object which is it's owner and is responsible for deallocating it. Your code needs to have clear semantics for transferring ownership (e.g. a function createNode() would expect its caller to destroy the node).
In your code nodes are both deleted by the list and by each element. This means everything gets deleted twice (or more). In your particular case this is the sequence of events on destruction of doublylinkedlist:
doublylinkedlist deletes its first element.
The destructor of the first element deletes its previous element, this is null so has no effect
The destructor of the first element deletes its next element (the second element).
The destructor of the second element deletes its previous element (the first element)
The destructor of the first element deletes its previous element, this is null so has no effect
The destructor of the first element deletes its next element (the second element).
This infinite loop eventually causes a stack overflow. Note that this isn't guaranteed to be the exact sequence of events as deleting an object twice is undefined behaviour so potentially anything could happen.
The simple fix is to remove the element destructor and have the list be responsible for the lifetime of all elements.
You should also modify your doublylinkedlist destructor as it will attempt to dereference a null pointer on the last element, you also don't need to delete tail as it should have already been deleted. E.g:
~doublylinkedlist(){
while(head!=0) {
auto temp = head;
head = head->next;
delete temp;
}
}
You shoudl also make sure you obey the rule of three/five). One way of doing this is to make use of smart pointers, for example using unique_ptrs your code could look like this:
#include <iostream>
#include <memory>
using namespace std;
typedef struct element {
element() {
data = 0;
next = nullptr;
prev = nullptr;
}
~element() {
cout << "element destructed" << endl;
}
int data;
std::unique_ptr< element > next;
element* prev;
} elem;
typedef struct doublylinkedlist {
doublylinkedlist() {
head = 0; tail = 0;
}
~doublylinkedlist() {
std::cout << "list destructed\n";
}
std::unique_ptr< elem > head;
elem* tail;
} doublyll;
doublyll ls;
void add() {
std::unique_ptr<elem> temp(new elem());
cout << "Enter an integer: ";
cin >> temp->data;
if (ls.head == nullptr) {//empty
ls.head = std::move(temp);
}
else {
if (ls.tail == nullptr) { //1-item list
ls.head->next = std::move(temp);
ls.tail = ls.head->next.get();
ls.tail->prev = ls.head.get();
}
else {
temp->prev = ls.tail;
ls.tail->next = std::move(temp);
ls.tail = ls.tail->next.get();
}
}
}
void report() {
if (ls.head == 0) cout << "List is empty!" << endl;
else {
elem *temp = ls.head.get();
do {
cout << temp->data << endl;
temp = temp->next.get();
} while (temp != 0);
}
}
int main() {
report();
add();
add();
add();
report();
add();
return 0;
}
The ownership of elements is now explicit, the list owns head and head owns its next node which owns its next node etc. Destroying the list automatically destroys the first node which automatically destroys the second node etc. In this code you can actually omit the destructors completely. This should also help to prevent memory leaks, for example if you decide to add some error checking to add the unused temp element gets automatically deleted:
void add() {
std::unique_ptr<elem> temp(new elem());
cout << "Enter an integer: ";
cin >> temp->data;
if (!cin || temp->data > 100) {
cout << "invalid input value\n";
return; // temp is automatically deleted here
}
...
}

Inserting a single element in a linked list gives a segmentation fault - C++

The below code intends to perform insertion of a single element in a linked list and then print it. Although, I am getting a segmentation fault while printing the value in main function. Could you please help me identify what is wrong with it ?
I have tried to print the value of data in the insert function and it works fine which means the creation of new node and assignment of the value to it is working fine.
#include<iostream>
using namespace std;
struct Node {
int data;
Node* next;
};
//insert a new node
Node* insertNode(int data,Node* head)
{
Node* cNode = head;
if (!head)
{
head = new Node;
head->data = data;
head->next = NULL;
}
else
{
while(cNode->next)
{
cNode = cNode->next;
}
cNode->next = new Node;
cNode->next->data = data;
cNode->next->next = NULL;
}
return head;
}
// print a list
void print(Node* head)
{
/*while(head->next)
{
cout << head->data << " ";
head = head->next;
}*/
cout << "printing data" << endl;
cout << "data : " << head->data;
}
int main()
{
cout << "inside main" << endl;
Node* aNode = NULL;
insertNode(2,aNode);
print(aNode);
return 0;
}
I expect the print function to print the value of data for the single node that I created .
Your head parameter in insertNode function should be a reference (or a pointer to pointer to Node). Beacause in the current form, it is an input parameter, but you need to be in-out parameter. It means that in the current code, your aNode variable is NULL and is always stays NULL.
I recommend this:
void insertNode(int data, Node &head)
Then you create an object in main this way: Node aNode;
It will allow you to update the existing variable directly and you don't need a return value. Also, this way it will be a little bit more C++like, your original code is more like a plain C code.
Or if you want to write it in plain C:
void insertNode(int data, Node **head)
Then you change the call from main: insertNode(2, &aNode);

Linked lists problems

I am trying to teach myself c++ and I am really confused with linked lists. I have been reading through textbooks and looking online but I am really confused how they work. I found an exercise online that I have been trying to figure out, but I am not getting anywhere with it.
Here is the list.h file:
struct node
{
int val;
struct node *next;
};
int length(struct node *);
void push(struct node **, int); //add to front of list
void append(struct node **, int); //add to rear of list
void print(struct node *, int);
I am having a hard time trying to write the functions for length, push and append.
A linked list is simply a string of Node classes string together, with each owning a pointer whose address is that of the next Node class in the list.
It's pretty simple if you think of it this way:
Coliru: http://coliru.stacked-crooked.com/a/5e71c5e31b58673c
#include <iostream>
//Proper encapsulation is not included for terseness and clarity
class Node {
public:
int num;
Node* next;
Node(int n) :
num(n),
next(nullptr) {
};
~Node() {}
};
int main() {
Node a(0);
Node b(1);
Node c(2);
Node d(3);
Node e(4);
//String the nodes together, linking like metal chainlinks
a.next = &b;
b.next = &c;
c.next = &d;
d.next = &e;
//Can you see how the "link" actually works here?
//Each Node's "next" pointer points to the next node.
std::cout << "Node a: " << a.num << std::endl;
std::cout << "Node b: " << a.next->num << std::endl;
std::cout << "Node c: " << a.next->next->num << std::endl;
std::cout << "Node d: " << a.next->next->next->num << std::endl;
std::cout << "Node e: " << a.next->next->next->next->num << std::endl;
//What if I were to point e to the start of a?
e.next = &a;
std::cout << "Node e->next: " << e.next->num << std::endl;
//It's node a!
//Node e.next is now accessible through the linked list:
std::cout << "Node e->next = a.next->next->next->next->next: " << a.next->next->next->next->next->num << std::endl;
//Usually people just use a for loop for this type of stuff.
//Let's use a lambda function to write one right here:
auto index_func = [](Node* head, size_t index) {
Node* current = head;
Node* next = head->next;
for (int i = 0; i < index; ++i) {
if (next != nullptr) {
//Hey, look at the pointers fly!
current = next;
next = current->next;
} else {
std::cout << "Whoops, we hit a null pointer before we got to our index!" << std::endl;
break;
}
}
return current->num;
};
//This is the same as finding the 6th node in the list (but since it's zero-indexing it's [5])
std::cout << index_func(&a, 5) << std::endl;
//We can also continue to do this:
std::cout << index_func(&a, 499) << std::endl;
//This is me accessing the 500th element, which, since our back links to our head node, it's the 4th node, d.
return 0;
}
You can probably imagine the other shenanigans we can do with linked lists if we decide to insert a Node between a or e simply be reassigning pointers.
void push(struct node **list, int newVal) { //add to front of list
struct node* firstNode = *list;
struct node* newNode = (struct node*) malloc(sizeof(struct node));
if (newNode == NULL) abort();
newNode->val = newVal;
newNode->next = firstNode;
*list = newNode;
}
void append(struct node **list, int newVal){ //add to rear of list
if (*list == NULL) {
push(list, newVal);
return;
}
/* Locate last node in list*/
struct node* curNode = *list;
while (curNode->next != NULL)
curNode = curNode->next;
/* Add a new node at the end of the list */
struct node* newNode = (struct node*) malloc(sizeof(struct node));
if (newNode == NULL) abort();
newNode->val = newVal;
newNode->next = NULL;
curNode->next = newNode;
}

c++ node list - NULL test not working

I wanted to test the following code (which works fine for a non-null list) to see what would happen in the case of an empty list (in which case the head would be null).
hence the code which applies to filling the list is commented out..
But for some strange reason, the test for NULL in print_nodes() just doesnt seem to work. ive added some debug cout calls to see (and also checked using gdb) but whilst the value does indeed appear to be NULL, any if statements dont seem to test the equivalence properly..
any idea why?
many thanks!
#include <iostream>
using namespace std;
struct node {
char dat;
node *nextPtr;
};
//inserts new node and returns pointer
node* new_node(char data, node* prevNode);
//adds a new node at the head ofthe list
void new_head (node *head_, char dat_);
//inserts new node after *before
void insert_node (node *before, char dat_);
//runs through and prints the list - requires first node (head)
void print_nodes (node *head);
int main() {
cout <<endl << endl;
cout << endl << "*******************RUN******************" <<endl <<endl;
node* head = NULL;
if (head == NULL) {
cout << "head null"; //this works here
}
//head non-standard
// node* head = new node;
// head->dat ='a';
/*
node* b = new_node('b', head);
node* c = new_node('c', b);
node* d = new_node('d', c);
node* e = new_node('e', d);
node* f = new_node('f', e);
*/
print_nodes(head);
insert_node(head,'N');
print_nodes(head);
cout << endl << "*******************END RUN******************" <<endl;
return 0;
}
node* new_node(char data, node* prevNode) {
node* tempPtr = new node;
tempPtr->dat = data;
tempPtr->nextPtr = NULL; //standard
prevNode->nextPtr = tempPtr;
return tempPtr;
}
void new_head (node *head_, char dat_) {
}
void insert_node (node *before, char dat_) {
node* tempPtr = new node;
tempPtr->dat = dat_;
tempPtr->nextPtr = before->nextPtr;
before->nextPtr = tempPtr;
}
void print_nodes (node *head) {
node* tempPtr = head;
cout << "\nPrinting nodes..." <<endl;
if (tempPtr == NULL) { //this test is not working.. why?
cout << "tempPtr is NULL";
return;
} else { //only run in the non null case
for (tempPtr; tempPtr != NULL; tempPtr = tempPtr->nextPtr) {
cout << "Current node content: " << tempPtr->dat <<endl;
}
}
}
You have a problem: head was not allocated, but insert accesses its "next element":
before->nextPtr = tempPtr;
head is passed in as before, and you didn't allocate memory for head. Hence you dereference a NULL pointer here.
Could it be that your application crashes as a result, and the printout to cout isn't done because cout is buffered?
Try to:
Remove the call to insert
Change cout to cerr (unbuffered)
Report the results of these changes.
allocate head before insertion :
node * head = new node;
memset(head, 0, sizeof(node));
The code works for me using g++ 4.4.1 on windows. The message is displayed and then it crashes, because of other issues in the code. You are probably not seeing the message because the crash occurs before the output buffer containing the message is flushed.
In general, it is a good idea to write diagnostic messages to standard error (cerr) rather than standard output, as the error stream is not buffered.