printing a (singly) linked list in c++ - 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.

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.

Single Linked List not working (C++)

The following code builds correctly but causes the program to crash when I run it. Can someone please tell me whats wrong with it. I suspect that there is something wrong with the DeleteNode function.
#include <iostream>
#include <cstdlib>
using namespace std;
class list {
private:
typedef struct node {
int data;
node* next;
}* nodePtr; //this means that 'nodePtr' will mean a pointer to the struct node
nodePtr head;
nodePtr current;
nodePtr temp;
public:
list() { //constuctor
head = NULL;
current = NULL;
temp = NULL;
};
void AddNode(int addData) //to add a particular data value
{
nodePtr n= new node;
n->next = NULL;
n->data = addData;
if (head != NULL) { //if a list is already set up
current = head;
while (current->next != NULL) { //to get to the last node in the list
current = current->next;
}
current->next = n;
}
else { // if list is not created
head = n; //new node is front of the list
}
}
void DeleteNode(int delData) //to delete a particular data value
{
nodePtr delPtr = NULL;
temp = head;
current = head;
while (current != NULL && current->data!=delData) { //pass through whole list && find value
temp = current;
current = current->next;
}
if (current = NULL) { //data value not found in list
cout << delData << " was not in the list." << endl;
delete delPtr; //to free up memory space
}
else {
delPtr = current;
current = current->next;
temp->next = current; //to reconnect list
if (delPtr == head) {
head = head->next;
temp = head;
}
delete delPtr;
cout << "The value " << delData << "was deleted." << endl;
}
}
void PrintList() //to print all the data values
{
current = head;
while (current != NULL) { //to go through the data valued of the list
cout << current->data << endl;
current = current->next;
}
}
};
int main()
{
list Shahzad;
Shahzad.AddNode(2);
Shahzad.AddNode(78);
Shahzad.AddNode(28);
Shahzad.AddNode(2398);
Shahzad.DeleteNode(78);
Shahzad.PrintList();
return 0;
}
Your first problem is with the following line:
if (current = NULL)
You're actually assigning null to current at this point.
This should actually be:
if (current == NULL)
Firstly, few code and file management remarks: consider separating your code into .h file where class members are declared and .cpp where class members are implemented, this will make your class easy to comprehend and possible errors will be easier to locate.
Secondly, a general advice when dealing with structures containing pointers is attention to proper resource management, i.e. pointer definitions, initialisations and deletions should be dealt with caution. If you are novice, consider the use of already provided smart pointer facilities like: std::unique_ptr which will "retain sole ownership of an object through a pointer and destroys that object when the unique_ptr goes out of scope"
Thirdly, use debugger to get rid of trivial errors like:
if (current = NULL)
which by the way contains additional inaccuracy expressed in the use of NULL instead of the pointer literal nullptr.
Lastly, check each of the member functions separately after you finish the initial implementation and only then proceed with further class expansion, otherwise you risk the accumulation of errors from multiple sources which will make your job very difficult
In your delete function in the case of which the node isn't found, you are deleting delPtr.
However, delPtr was never instantiated or assigned so you are trying to delete something that doesn't exist.
Always enclose pointer deletions in if statements to avoid this issue. Try this:
if (delPtr) delete delPtr;
Apart from all the suggestions here, you can use some safe programming practices to catch bugs early.
For ex: you wrote
if (current = NULL)
Instead, try writing the value being checked on the LHS and the variable on the RHS like this:
if ( NULL == current)
Here, if you mistyped
if (NULL = current)
the compiler will complain. You have a compile time bug now instead of a run-time one. This is far easier to find and debug.

When do I need to use the new operator when declaring nodes in C++?

When creating a node in c++, when do I need to use the new operator to ensure that memory is available to allocate.
For instance, this function does not use new when declaring the node pointer NewNode used to find the end of an existing linked list for purposes of adding a node to the end of the list, however it does use new when actually adding the node to the end of the list. Is this because the node pointer is being used as a non-dynamic memory allocation that points to other memory that has already been allocated dynamically or for some other reason? Would it be incorrect syntax or logic wise to use the new (nothrow) in front of the NewNode declaration?
typedef Node* NodePtr; /*a type definition for NodePtr for ease of use in `the larger program this function is a part of*/`
void AddNode(char NewChar, NodePtr List)
{
NodePtr NewNode = List; //make NewNode point to List
while (NewNode->Link != NULL) //find end of linked list
NewNode = NewNode->Link;
NewNode->Link = new (nothrow) Node; //create a new Node at the end of the list
if (NewNode->Link == NULL) //make sure Node was created
return;
NewNode = NewNode->Link; //make NewNode point to the Node just created
NewNode->Ch = NewChar; //fill Ch part of NewNode
NewNode->Link = NULL; //make sure the list ends with NULL
}
void TestAddNode(NodePtr List)
{
char NewChar;
cout << "\n\n---------------- Testing AddNode -------------------\n\n";
cout << "Character to be added? ";
NewChar = cin.get();
cin.ignore();
if (NewChar == '\n') // User pressed just enter key.
{
cout << "Aborting AddNode...";
return;
}
cout << NewChar;
cout << " -- Adding \'" << NewChar << "\'";
AddNode(NewChar, List);
cout << "\n\nThe new list: ";
ShowList(List); //show list is another function that outputs the list
}
You would use new only when dynamically-allocating new memory for storing a new node. In your case, NewNode is just pointing to the existing memory pointed to by List, so this is not the right place for using the new operator.

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.

Why does iteration on my list fail?

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.