Why does iteration on my list fail? - c++

I'm currently working my way through the Stanford open CS106B, and I'm running into a problem on Assignment 3, Part B. I am given a struct Node as follows:
struct Node {
string name; // my person's name
string killer; // who eliminated me
Node* next; // ptr to next node
Node(string name, Node* next) {...}
};
I have to implement a class that makes a list of Nodes. I have the constructor working properly, but when I try to iterate through the list, my program crashes. My iteration code:
void AssassinsList::printGameRing() {
Node* current;
for(current = ring; current->next != NULL; current = current->next) {
cout << endl << " " << current->name << " is targeting " << current->next->name;
}
cout << endl << " " << current->name << " is targeting " << ring->name << endl;
}
However, if I use a for-loop to loop the number of times I know I need to for a certain list length, it works. Help? The link to the assignment pdf: http://www.stanford.edu/class/cs106b/homework/3-tiles-assassins/spec.pdf
Thanks!

I am guessing that you don't initialize * next to nullptr. So for all the links you setup between nodes it is fine, but the last object in the list points to garbage.
Sorry, nullptr is c++11. If your compiler older then its just NULL.

There's a chance that if cur is NULL or doesn't point to anything, you could be dereferencing a bad pointer and therefore crashing your program. The other option is that as woolstar pointed out, you don't have a terminating node in your list (that points to NULL.) Observe the following code:
Node* head = new Node{0};
Node* cur = head;
for (int i = 1; i <= 10; i++)
{
cur->next = new Node{i};
cur = cur->next;
}
// Set terminating node
cur->next = nullptr;
// We'll iterate until cur is null
// So if we access cur->next
// It won't result in undefined behavior
for (cur = head; cur != nullptr; cur = cur->next)
{
std::cout << cur->value;
}
// cur should be nullptr now
if (!cur)
std::cout << "end of list";

You can also use 0. Yeah, it's not as cool as nullptr, but it's supported. Fixed constructor:
Node(string name_, Node* next_=0): name(name_), next(next_) {}

The fact a fixed length loop works, but a NULL terminated loop doesnt work shows that its likely you have an invalid address in the last Node's next field.
I would expect your problem comes from either your Node constructor or your list code or the interplay between them.
Try setting next to 0/nullptr in the Node constructor, that should help.
Alternatively, have your list set the next field to 0 when you add the first element to the list, or add any element to the end of the list.

Related

Improve my solution to basic C linked list management functions

I would appreciate some help relative to my code solution, which deals with linked list management in C. I'll already declare the only strange thing with my request: I am writing a C++ file, but I am actually mostly leveraging C resources (malloc(), free(), etc.); that said, given the basic code I provide, I am confident no one will have trouble with that.
I want to write a function to add elements to the end of the list and one to delete elements from it, that work in any edge case. Given my desire, the removal function was the one that I struggled the most with, but also the one that made me realize how little I am understanding pointers.
I will now share the code I produced, that should be working fine, but:
It can surely be greatly improved both in terms of clarity and performance
I think that showing it to the community will highlight many of the flaws present in my solution
// The plan is to create a linked list and to be able to add and delete its elements
#include <iostream>
using namespace std; // I can write output lines as cout << "Hi!", rather than std::cout < "Hi!"
#include <cstdlib> // needed for malloc() in C++
struct node {
int data;
node* nextPtr; //"struct node* nextPtr;" : This would be the syntax for plain old C: you always have to type the "struct" keyword
};
node* createElement(int data) {
node* newElemPtr = (node*)malloc(sizeof(node)); // the "(node*)" cast is required by C++, and is not used in C
newElemPtr->data = data;
newElemPtr->nextPtr = NULL;
return newElemPtr;
}
void appendElement(int data, node** head) { // Adds a new node at the end of the list
// I pass as argument a pointer to pointer (double pointer) to node, so that I can edit the head node
// if the list is empty, without having to return a new node pointer as head: my function indeed features
// "void" in its signature
node* elemPtr = NULL;
elemPtr = createElement(data); // elemPtr is a pointer to the new node
if (*head == NULL) {
*head = elemPtr;
}
else {
node* currPtr = *head; // currPtr is the temporary variable that visits each node of the linked list
while (currPtr->nextPtr != NULL)
currPtr = currPtr->nextPtr;
currPtr->nextPtr = elemPtr; // Set last element's nextPtr to "elem", i.e., a pointer to the new element
}
};
void removeElement(int data, node** head) { // Remove all the nodes whose data content matches the "data" argument
int presence_flag = 0; // Flag used to check whether the required data is present at all in the linked list
if (*head == NULL) {
return;
}
else {
node* currPtr = *head;
node* prevPtr = *head;
while (currPtr != NULL) {
// This is the case in which I find a node to delete (it matches the "data" query), and it is not the first of the list
if (data == currPtr->data && currPtr != *head) {
prevPtr->nextPtr = currPtr->nextPtr; // Link the node ahead of the one to delete with the one behind
free(currPtr);
currPtr = prevPtr; // In the next loop, I will resume the analysis from the previous node, which now points to an unvisited one
presence_flag = 1;
}
// This is the case in which I find a node to delete and it is the first of the list
else if (data == currPtr->data && currPtr == *head) {
// This is the case in which I have to delete the first node, but the list features other nodes
if (currPtr->nextPtr != NULL){
*head = currPtr->nextPtr; // Move *head forward
currPtr = *head; // Do the same with currPtr, in order not to break the while() loop
free(prevPtr); // As *head has already been re-assigned, I leverage prevPtr to delete the old *head
presence_flag = 1;
}
// This is the case in which I have to delete the first and only node of the list
else {
*head = NULL;
currPtr = *head;
presence_flag = 1;
}
}
// This is the case in which the current node does not match the queried "data" value
else{
prevPtr = currPtr; // Update prevPtr
currPtr = currPtr->nextPtr; // Move currPtr forward
}
}
}
if (presence_flag == 0)
cout << "There is not any node with value " << data << " in the linked list.\n\n";
// Q1: Am I causing any memory leak by using *head == NULL instead of free(*head)?
// Q2: Should I free() everythin before ending the main(), at least as a good practice?
// Q3: Is there a way to make this function by not using a double pointer as input and by also keeping "void" as return value?
// Of course, it should still work in the tricky edge case of the last element in the list that has to be deleted
};
void printLinkedList(node* head) { // Here I return nothing, so I can freely edit "head" (i.e., there is no need for a temporary pointer)
if (head == NULL) {
cout << "The linked list is empty.\n";
}
else {
int elemCounter = 0;
while (head != NULL) {
elemCounter += 1;
cout << "elem N. " << elemCounter << ": data value = " << head->data << "\n"; // head->data is equal to (*head).data
head = head->nextPtr;
}
}
};
int main(int argc, char* argv[])
{
//cout << "Size of a single node of the list = " << sizeof(node) << "\n";
// == 16. On a 64 bits machine, an int ("data") requires 4 bytes.
// The pointer requires 8 bytes; the remaining 4 bytes are padding
node* head = NULL;
appendElement(1, &head);
appendElement(2, &head);
appendElement(3, &head);
printLinkedList(head);
cout << "\nRemoving element with data value = 1...\n\n";
removeElement(1, &head);
printLinkedList(head);
cout << "\nRemoving element with data value = 2...\n\n";
removeElement(2, &head);
printLinkedList(head);
cout << "\nRemoving element with data value = 3...\n\n";
removeElement(3, &head);
printLinkedList(head);
cout << "\nRemoving element with data value = 4...\n\n";
removeElement(4, &head);
printLinkedList(head);
cout << "\nRemoving element with data value = 1...\n\n";
removeElement(1, &head);
printLinkedList(head);
cout << "\nRemoving element with data value = 2...\n\n";
removeElement(2, &head);
printLinkedList(head);
return 0;
}
As you can see from the comments embedded in the code, I have 3 doubts that captured my interest while coding the node removal function:
Q1: Am I causing any memory leak by using *head == NULL instead of free(*head)?
Q2: Should I free() everything before ending the main(), at least as a good practice?
Q3: Is there a way to make this function by not using a double pointer as input and by also keeping "void" as return value? Of course, it should still work in the tricky edge case of the last element in the list that has to be deleted
I hope that featuring these "additional" questions is something reasonable to put here, as maybe someone in the future may have the same doubts I had.
I know there are plenty of ready-to-copy-and-paste solutions for my task, but I think I can really learn this stuff if I see why my precise design choices are not optimal/wrong.
I thank everyone for the time spent reading this.
There are many duplicated code. Also the function should not output any message. It is the caller of the function that decides whether to output a message. So the function should have the return type bool if you are considering the program as a C++ program or bool or int if you are considering the program as a C program.
The function removeElement invokes undefined behavior because in its paths of execution you are not always resetting correctly values of the pointers currPtr and prevPtr after deleting a node.
For example after this code snippet
if (data == currPtr->data && currPtr != *head) {
prevPtr->nextPtr = currPtr->nextPtr; // Link the node ahead of the one to delete with the one behind
free(currPtr);
currPtr = prevPtr; // In the next loop, I will resume the analysis from the previous node, which now points to an unvisited one
presence_flag = 1;
}
prevPtr and currPtr will be equal each other.
I would define the function the following way
int removeElement( node **head, int data )
{
int deleted = 0;
while ( *head )
{
if ( ( *head )->data == data )
{
deleted = 1;
node *current = *head;
*head = ( *head )->next;
free( current );
}
else
{
head = &( *head )->next;
}
}
return deleted;
}
As for your question
Q3: Is there a way to make this function by not using a double pointer
as input and by also keeping "void" as return value? Of course, it
should still work in the tricky edge case of the last element in the
list that has to be deleted
then in C you can not achieve this. In C++ you can pass the pointer to the first node by reference. In C passing by reference means passing an object indirectly through a pointer to it. So in C you have to use a double pointer in such a case.
Of course just setting a pointer to NULL without freeing data pointed to by the pointer that was dynamically allocated produces a memory leak. And you should free all the allocated memory then it is not required any more.

Printing nodes from REAR to FRONT enters infinite loop

I am trying to output the elements from each node starting from right (rear/tail) to left (head/front). However, my program enters an infinite loop that displays the same element over and over again. Despite its infinite loop, the function that I created DisplayFromLeftToRight() (found below the DisplayFromRightToLeft() function) works like a charm, but this doesnt...
void DisplayFromRightToLeft()
{
node *newnode = rear;
int num = 1;
while (newnode != NULL)
{
cout << "Node # " << num << ": " << newnode->data << endl;
newnode = newnode->previous;
num++;
}
return;
}
This is the working code for printing element from each node from LEFT to RIGHT..
void DisplayFromLeftToRight()
{
node *newnode = front;
int num = 1;
while (newnode != NULL)
{
cout << "Node # " << num << ": " << newnode->data << endl;
newnode = newnode->next;
num++;
}
return;
}
If you believe that my DisplayFromRightToLeft() function is correct, I assume that the problem is from the INSERT function, take a look:
void INSERT(int _data)
{
node *newnode = new node;
newnode->data = _data;
newnode->next = NULL;
newnode->previous = newnode;
rear = newnode;
node *index = new node;
index = front;
if (isEmpty())
front = newnode;
else
{
while (index->next != NULL)
{
index = index->next;
}
index->next = newnode;
}
}
Looks like INSERT always sets previous to a valid address, so your while (newnode != NULL) loop will never end, because it sets newnode = newnode->previous each time.
You are correct that the problem seems to be in your INSERT function, and/or any other code that determines what is in your list.
Your Display...() functions look OK as far as not looping, by themselves, but by making them rely on a while(someNode != NULL) loop, they are dependent on the assumption that the list data is well-formed. Specifically, the first node must have a previous pointer to NULL, and the last node must have a next pointer to NULL, or else one of those Display functions will loop until it finds a NULL.
Looking at the INSERT function, if you follow the steps, you will see that it assigns a new valid address to newnode, and then sets previous to that valid address, while next gets NULL, and it can assign next to something else. How would previous ever be NULL? Previous also points to the inserted node itself, which looks like any loop following previous is just going to keep looking at the same node.
Whenever working with linked lists that I implement, I always step through the code and diagram what is going on - on paper is best, rather than just imagination. Only draw things you actually have your code do. Otherwise, you are probably assuming the resulting list data is what you intended, and not what you've actually coded.
You should change:
newnode->previous = newnode;
To:
newnode->previous = rear;
Line:
newnode->previous = newnode;
has no sense. It is like saying that I am my own father.

Trying to understand pointers and double pointers

I'm trying to implement a simple linked list in C++. I can create nodes and they seem to link themselves correctly. My question involves the listIterate() function, but I've attached the entire code here in case it is needed.
#include <iostream>
using namespace std;
//Wrapper class which allows for easy list management
class LinkedList {
//Basic node struct
struct node {
int data;
node *link;
};
node *head; //Pointer to the head (also referred to as root) node, or the first node created.
node *current; //Pointer to the /latest/ node, or the node currently being operated on.
node *tail; //Pointer to the tail node, or the last node in the list.
public:
//Default constructor. Creates an empty list.
LinkedList() {
head = NULL;
current = NULL;
tail = NULL;
cout << "*** Linked list created. Head is NULL. ***\n";
}
//Default destructor. Use to remove the entire list from memory.
~LinkedList() {
while(head != NULL) {
node *n = head->link;
delete head;
head = n;
}
}
/*
appendNode()
Appends a new node to the end of the linked list. Set the end flag to true to set the last node to null, ending the list.
*/
void appendNode(int i) {
//If there are no nodes in the list, create a new node and point head to this new node.
if (head == NULL) {
node *n = new node;
n->data = i;
n->link = NULL;
head = n;
//head node initialized, and since it is ALSO the current and tail node (at this point), we must update our pointers
current = n;
tail = n;
cout << "New node with data (" << i << ") created. \n---\n";
} else {
//If there are nodes in the list, create a new node with inputted value.
node *n = new node;
n->data = i;
cout << "New node with data (" << i << ") created. \n";
//Now, link the previous node to this node.
current->link = n;
cout << "Node with value (" << current->data << ") linked to this node with value (" << i << "). \n---\n";
//Finally, set our "current" pointer to this newly created node.
current = n;
}
}
/*
listIterate()
Iterates through the entire list and prints every element.
*/
void listIterate() {
//cursor
node *p;
//Start by printing the head of the list.
cout << "Head - Value: (" << head->data << ") | Linked to: (" << head->link << ") \n";
p = head->link;
cout << *p;
}
};
int main() {
LinkedList List;
List.appendNode(0);
List.appendNode(10);
List.appendNode(20);
List.appendNode(30);
List.listIterate();
}
Now, I'll refer to this method, listIterate().
void listIterate() {
//cursor
node *p;
//Start by printing the head of the list.
cout << "Head - Value: (" << head->data << ") | Linked to: (" << head->link << ") \n";
p = head->link;
cout << *p;
}
The command cout << *p; throws an error and I believe this is why: At this point, p is pointing to head->link, which is another pointer which points to the link field of my head node. Now, I understand if I dereference p at this point in the program, there would be no actual value in head->link as it points to a variable.
To me, if I dereference p twice (**p), it should follow the pointer twice (p -> head->link -> The value of the second node in the linked list (10). However, dereferencing p twice throws this error.
LinkedListADT.cc:89: error: no match for ‘operator*’ in ‘** p’
Can anyone help me understand why this is the case? Is this an illegal operation? Is it performed in another way that I'm not familiar with?
cout << *p tries to print a node object. Since no print operation is defined for node objects (ie. no operator<< for output streams), the attempt to print it fails. What you're probably looking for is:
cout << p->data;
For your second point, the statement can be broken down thus:
**p == *(*p)
So the first star dereferences p, returning a node. The second star attempts to dereference the result of that operation, but since a node is a struct and not a pointer, the compiler complains.
Hope this helps.
Your node class is missing an operator *, so the construct **p when p is of type node * is semantically ill-formed. To look at an example of overloading operator *, look at examples of implementing smart pointers.
**p Does not "follow the pointer twice". The operation simply tries to dereference p twice.
p is a pointer to a node. The first dereference (*p) will evaluate to the node that was pointed to by p. The second dereference (**p) will cause an error, because a node is a struct and not a pointer and has no overloaded operator* defined.
If you wish to dereference the pointer to the next node:
*(p->link)

Attaching nodes to a tree in C++ (Reference and pointer help.)

I am writing a balancing binary tree for class, but I am having some confusion as to how to use pointers and references in C++ (coming straight from Java). The code below results in a segfault, because no node has actually been added to the tree, curr has just been switched to the new Node. How would I go about making it so that the new Node goes to where curr is pointing to on the tree, rather than just reassigning curr?
void BalancedTree::insert(int input)
{
cout << "Insert started\n"; //DEBUG
Node* trailingNode;
Node* curr;
curr = this->root;
while(curr != NULL){
cout << "Addloop\n"; //Debug
if(input < curr->data){ //input smaller than current
cout << "Left\n"; //DEBUG
trailingNode = curr;
curr = curr->left;
}else{ //input larger than current node
cout << "Right\n"; //DEBUG
trailingNode = curr;
curr = curr->right;
}
}
insert(curr, input);
cout << "test" << endl;
cout << root->data << " added\n"; //DEBUG
// curr->parent = trailingNode; //Set the parent
size++; //Increase size
}
//Helper method
void BalancedTree::insert(Node*& curr, int input)
{
curr = new Node(input);
}
If we have the following tree and attempt to insert the value 3:
2
/ \
1 <-- --> 4
/ \ / \
N N N N
(N is NULL) after the while loop as posted has completed:
trailingNode is pointing to the Node with value 4
curr is NULL (the left branch of Node with value 4)
then insert() assigns a new Node to curr but never attaches it to the left branch of the Node with value 4.
To attach you could change the call to insert():
insert(input < trailingNode->data ?
trailingNode->left :
trailingNode->right,
input);
You need to handle the case when the tree is empty. There are other ways that this could be achieved but hopefully this will point you in the right direction.
You can do it with a double pointer. Make cur actually reference (in C++ case point to) the last node reference you need to change:
Node ** curr;
curr = &this->root;
while(*curr != NULL){
cout << "Addloop\n"; //Debug
if(input < (*curr)->data){ //input smaller than current
cout << "Left\n"; //DEBUG
trailingNode = curr;
curr = &((*curr)->left);
}else{ //input larger than current node
cout << "Right\n"; //DEBUG
trailingNode = curr;
curr = &((*curr)->right);
}
}
insert(curr, input);
cout << "test" << endl;
cout << root->data << " added\n"; //DEBUG
// curr->parent = trailingNode; //Set the parent
size++; //Increase size
}
//Helper method
void BalancedTree::insert(Node** curr, int input)
{
*curr = new Node(input);
}
I think this should do the trick for you, but have not tried it - just edited in the edit here, so please forgive me if I made some simple coding error.
1) initialize the pointers to NULL:
Node* trailingNode = NULL;
Node* curr = NULL;
2) no need to explicitly check for NULL in the while loop:
while(curr){
3) The call to insert(curr, input) is always called with a NULL pointer! And even if it would not be NULL that pointer is still just a regular pointer having no relation with the node you retrieved it from. Taking a reference to it will not fix this. Instead you need to create a new node and assign it to either the left or right of the trailingNode, f.e.:
if (!curr->right) {
curr->right = new Node (input);
break; // exit while
}
Pointers are value types, similar to references or ints in Java.
Passing variables by reference creates an alias to that variable, so you can change its value in the function. When you do insert(curr, input);, it modifies the value of the pointer variable curr, making it point at a newly created node. The more or less equivalent situation in Java would be:
Node curr;
if([...]) {
[...]
curr = curr.left;
}
else {
[...]
curr=curr.right;
}
[...]
curr = new Node();
Now you can see how this doesn't actually insert anything into the tree. Now, if you want a variable to indicate an actual left or right member of a node, instead of just having the same value (pointing at the same object) as that member, you need to have a pointer to the member (field) itself - as the member is of a type 'pointer to Node', a pointer to the member would have to be a pointer to (pointer to Node), or in C++ notation Node**.
Now if you pass that 'pointer to pointer' to a function, you can modify through it the value of the referenced left or right member. This also means you don't need to modify the value of curr (and therefore pass it in by reference) - it will still point to the same left or right member (or possibly the root member of your BalancedTree object), only that member's value will be changed to point to the newly created element.

printing a (singly) linked list in c++

OK, first I have my node structure
struct node {
string s;
node * next;
};
And It's located within a class
class strSet{
private:
node * first;
And I can construct the list, and i've made checks to see it's being constructed (it is), but when i try and print it.. "Empty Set" is printed
This is my code to "print" it: (I've tried many variations of declaring a temp pointer, and still nothing)
node *temp = new node;
temp = first;
if (temp == NULL) cout << "Empty set" << endl;
else {
// node * temp = new node;
while (temp != NULL){
cout << temp->s << endl;
temp = temp->next;
}
}
Any help is appreciated, Thanks
EDIT: I have a function that makes a singleton list (this is for an assignment), the code is:
node *first = new node;
first->s = s;
cout << first->s << endl;
first->next = NULL;
The third line prints out the element when I add it
And yes i know there is a memory leak
node *temp = new node;
this line is unnecessary and leaks memory;
The rest of the printing routine is correct, and therefore if "Empty Set" is printer therefore the set IS empty
From the small quantity of code you posted, it should work, so my guess would be that something is wrong with the construction of the list.
Now, there are some incoherences in your code - the useless "new node" for temp, as stated, but also having your (temp == NULL) ; this test could be directly operated with "first". Of course, make sure the strSet initializes first to null.
Then only you'd create temp before the while() and after the else. It's more logical (and a bit more optimal, though you're not winning much there - but you'll gain in readability).
node *temp = new node;
temp = first;
can be condensed to -
node *temp = first ; // An unnecessary memory leak in earlier case.
Other than that print logic seems to fine. You didn't show the important part of how the linked list is formed.
node *first = new node;
first->s = s;
cout << first->s << endl;
first->next = NULL;
This is not a linked list at all. You are just creating an instance of type node* and just copying the s to it.