I'm currently working on a class project where we make a linked list and we're supposed to create a function that clears the list then deletes it (with "delete LIST_NAME;"). I have implemented the function as instructed by my professor, also forcing the list to become null after the delete. The function works within itself, but when it returns to the main function, the list gets a new value.
Is this sort of function just not possible in C++?
#include <iostream>
struct Node
{
int val;
Node* next;
};
struct LinkedList
{
int count;
Node* head;
Node* tail;
};
void Clear(LinkedList* list) {
Node* node = list->head;
Node* next = nullptr;
while (node != nullptr) {
next = node->next;
delete node;
node = next;
}
list->head = nullptr;
list->tail = nullptr;
list->count = 0;
}
void Destroy (LinkedList* list) {
Clear(list);
delete list;
list = nullptr;
std::cout << "\n(should be) Destroyed";
}
int main() {
//creating a list element
Node* node = new Node;
node->val = 'a';
node->next = nullptr;
//inserting the element onto list
LinkedList* list = new LinkedList;
list->count = 0;
list->head = node;
list->tail = node;
std::cout << "\nList: " << list;
Destroy(list);
std::cout << "\nList: " << list;
std::cout << "\nEND";
}
This is just a snip of my code but it shows what I mean. Using the debugger the list has the value 0x0 by the end of the function but in the main function it's assigned a new value as shown by the debugger.
You take list by value so it's local to the function.
If you'd like to make changes to it that are visible at the call site, take it by reference:
// `list` is now a reference to the pointer at the call site:
void Destroy(LinkedList*& list) {
Clear(list);
delete list;
list = nullptr; // this now sets the referenced `LinkedList*` to `nullptr`
std::cout << "\n(should be) Destroyed";
}
Related
How to reverse linked list using double pointer?
I was learning about double pointers and thought if we can reverse linked list using one pointer only.
Conversion to using a pointer to pointer left as an exercise for the reader. Also has some distinct shortcomings in terms of style.
#include <iostream>
struct node {
int data;
node *next;
};
node *reverse(node *list) {
node *prev = NULL;
node *next;
while (list) {
next = list->next;
list->next = prev;
prev = list;
list = next;
}
return prev;
}
void show_list(node *list) {
while (list != NULL) {
std::cout << list->data << ", ";
list = list->next;
}
}
int main() {
node *list = NULL;
for (int i=0; i<10; i++) {
node *n = new node;
n->next = list;
n->data = i;
list = n;
}
std::cout << "As built: ";
show_list(list);
list = reverse(list);
std::cout << "Reversed: ";
show_list(list);
return 0;
}
If you decide to modify a pointer you received as a parameter, it's probably easier to deal with a reference to a pointer than a pointer to a pointer though.
I am trying to implement a doubly linked list in C++ and have run across a problem.
#include <iostream>
#include <string>
struct Node
{
std::string data;
Node* prev_link;
Node* next_link;
Node(const std::string& data,Node* prev_link=nullptr, Node* next_link=nullptr)
: data{data},prev_link{prev_link},next_link{next_link} {}// constructor
};
Node* insert(Node* new_node,Node* old_node);// insert node before old node
Node* head(Node* node);// returns a pointer to the head i.e. the left end of the linked list
void print_list(Node* node);//takes the head pointer and executes iterative print
void kill_list(Node* tail_node);// deallocates memory by deleting the list
Node* insert(Node* new_node,Node* old_node)
{
if(new_node == nullptr) return old_node;
if(old_node == nullptr) return new_node;
new_node->next_link = old_node;// p of old node connect to new node
if(old_node->prev_link) old_node->prev_link->next_link = new_node;//n of old' node connect to new node if old' node exists
new_node->prev_link = old_node->prev_link;//p of new node connect to old` node
new_node->next_link = old_node;//n of new node connect to old node
return new_node;
}
Node* head(Node* node)
{
while(node->next_link != nullptr) node = node->next_link;
return node;
}
void print_list(Node* node)
{
while(node)
{
std::cout << node->data;
if(node = node->next_link) std::cout << "<->";// if next node is not an end node
}
}
void kill_list(Node* tail_node)
{
Node* temp;
while (tail_node)
{
temp = (tail_node->prev_link)?tail_node->prev_link:tail_node->next_link;
delete tail_node;
tail_node = temp;
}
std::cout << '\n' <<"List destroyed" << std::endl;
}
int main()
{
Node* alphabets = new Node("A");
alphabets = insert(new Node("B"),alphabets);
alphabets = insert(new Node("C"),alphabets);
print_list(alphabets);
std::cout << '\n';
std::cout << "Head:" << head(alphabets)->data << std::endl;
std::cout << "Adjacent:" << head(alphabets)->prev_link->data << std::endl;
kill_list(alphabets);
}
output:
C<->B<->A
Head:A
fish: “./test1” terminated by signal SIGSEGV (Address boundary error)
The head() function returns a pointer to the head node(in this case it's A).
The linked list as well as the head node is printed correctly but I cannot access the node adjacent to the head node. Cannot figure out what I am doing wrong. Any help would be appreciated.
Your error is because there is a null pointer for the neighbor of A. In your insert function, you have this if statement
if(old_node->prev_link) old_node->prev_link->next_link = new_node
However, in the case of A, there is no prev_link but you would still like to assign B. So replacing that with:
old_node->prev_link = new_node;
fixes the issue. However you might want to double check so that this corresponds to your desired logic.
The problem is due to the fact that the prev_link is not set for the head (the prev link is zero for every node), there is an error on the insert function, you never set the prev_link of the old node.
I am implementing a link list with cpp,what is wrong with the following code?
Every time i step into the function---AddToTail, the "list" can't get correct value. It changes it value to the new constructed node.
#include <iostream>
using namespace std;
struct Node
{
int value;
Node * next;
};
void AddToTail(Node* &list, int value)
{
Node newnode;
newnode.value = value;
newnode.next = NULL;
if (list == NULL)
list = &newnode;
else
{
Node * list1 = list;
while (list1->next != NULL)
{
list1 = list1->next;
}
list1->next = &newnode;
int a = 1;
}
}
int main()
{
Node *list=NULL;
AddToTail(list, 1);
AddToTail(list, 2);
AddToTail(list, 3);
while (list->next != NULL)
{
cout << list->value << endl;
list = list->next;
}
system("pause");
}
void AddToTail(Node* &list, int value)
{
Node newnode;
// Set up fields of newnode.
// Store address of newnode into some other data structure.
}
This is your issue. You are creating a node on the stack and this node will go out of scope at the end of the function. The reason it seems to be interfering with later node creations is because re-entering the function will almost certainly create newnode at exactly the same address as in the previous call.
If you want objects to survive function scope, you're going to need to allocate them dynamically, something like:
void AddToTail (Node *&list, int value) {
Node *newnode = new Node(); // create on heap.
newnode->value = value; // set up node.
newnode->next = nullptr;
if (list == nullptr) { // list empty,
list = newnode; // just create.
return;
}
Node *lastNode = list; // find last item.
while (lastNode->next != nullptr)
lastNode = lastNode->next;
lastNode->next = newnode; // append to that.
}
I've been stuck trying to figure out how I can implement a NODE based link list that can hold anything (via templates).
I've got the Node class ready and working(tested with my Stack class).
I was curious where I could be going wrong when making the function called insertAtIndex where I take in the data to store and the index at where it should be stored.
My Node class
template <class T>
class Node
{
public:
T *data; //the object information
Node<T> *next; //pointer to the next node element
Node()
{
next = 0;
data = 0;
}
};
Here's my Linked List class so far
template <class T>
class LinkedList
{
private:
Node<T> *head;
int count;
public:
LinkedList()
{
head = 0;
count = 0;
}
int getCount()
{
return count;
}
void insertAtIndex(T* dat, int index)
{
Node<T> * temp = new Node<T>(dat);
if(index == 0)
{
temp = head;
temp->data = dat;
temp->next = temp->next;
temp->next = temp;
delete temp;
count++;
}
else if(index <= count)
{
Node<T> *cursor = new Node<T>();
for(int i = 0; i < index - 1; i++)
{
cursor = cursor->next;
}
Node<T> * temp = new Node<T>();
temp->data = dat;
temp->next = cursor->next;
cursor->next = temp;
count++;
}
}
void Print()
{
// Temp pointer
Node<T> *tmp = head;
// No nodes
if ( tmp == NULL ) {
cout << "EMPTY" << endl;
return;
}
// One node in the list
if ( tmp->next == NULL ) {
cout << *tmp->data;
cout << " --> ";
cout << "NULL" << endl;
}
else
{
// Parse and print the list
do
{
cout << *tmp->data;
cout << " --> ";
tmp = tmp->next;
}
while ( tmp != NULL );
cout << "NULL" << endl;
}
}
};
You should add Node(T*) constructor to your Node class:
template <class T>
class Node
{
public:
T *data; //the object information
Node<T> *next; //pointer to the next node element
Node()
{
next = 0;
data = 0;
}
Node(T* newData) { // <<---------- Here it is
next = 0;
data = newData;
}
};
You need to rethink how you are adding nodes to the list. Here is your code with comments on what it is actually doing.
Node<T> * temp = new Node<T>(dat); // Create new node, good
if(index == 0)
{
temp = head; // Throw away pointer to new node, bad. temp is now head.
temp->data = dat; // Overwrite head's data, bad
temp->next = temp->next; // Set a variable to itself, does nothing.
temp->next = temp; // Change head's next to point to itself, bad
delete temp; // delete the head node, bad
count++;
}
What you actually want to do is:
Create a new node with the right data (you already do this)
If you are putting it at the start of the list:
Point the new node's next pointer to head
Change head to point to the new node
That's all - don't delete anything.
Once you have that working, move on to the more complicated part of adding a node to the middle or the list (your else part).
A debugger (or at least output statements) is essential for learning where your code is going wrong. You can look at the state of your variables at each point.
You might want to consider a base node class that only has a next pointer as a member, then an inherited class that adds a template data member. Common list functions could be used for the base class.
I am currently learning some C++ for a course I am taking in school. I have basic understanding of lvalues and rvalues, but I am unable to determine why I am receiving a compiler error.
I am creating a singly linked list and need to be able to reverse it. As per my assignment I have two classes. The first is the node and just holds an int as well as a pointer.
class Node {
int data;
Node *next;
public:
//Constructor
Node(int d) {
data = d;
next = NULL;}
//Set to next Node
void SetNext(Node *nextOne) {
next = nextOne;}
//Returns data value
int Data(){return data;}
//Returns next Node
Node *Next() {return next;}
};
Then I have a linked list class that has a header pointer and then a number of functions for adding, printing etc. the list.
class LinkedList {
Node *head;
public:
//Constructor
LinkedList(){head = NULL;}
void AddNode(int d) {
//Create a new Node
Node *newNode = new Node(d);
//Create a temporary pointer
Node *temp = head;
//If there are already nodes in the list
if(temp != NULL) {
//Parse through to the end of the list
while(temp->Next() != NULL) {
temp = temp->Next();}
//Point the last Node in the list to the new Node
temp->SetNext(newNode);
}
//If adding as the first Node
else{
head = newNode;}
}
void PrintList() {
//Temporary pointer
Node *temp = head;
//If there are no nodes in the list
if(temp == NULL) {
std::cout << "The list is empty" << std::endl;}
//If there is only one node in the list
if(temp->Next() == NULL) {
std::cout << temp->Data() << std::endl;}
//Parse through the list and print
else {
do {
std::cout << temp->Data();
temp = temp->Next();
}
while(temp != NULL);
}
}
//Returns the number of nodes in the list
int CountList() {
//Temporary pointer
Node *temp = head;
//Counter variable
int counter = 0;
//If the list is empty
if(temp == NULL) {
return counter;}
//Parse through Nodes counting them
else {
do {counter++;
temp = temp->Next();
}
while(temp != NULL);
}
return counter;
}
//Reverses the list
Node *ReverseList() {
//Initially set to NULL then tracks the new head
Node *marker = NULL;
//Tracks the next one in the list
Node *nextOne;
//Sets the first Node to NULL and then sets the last Node to point to
//the first one and rotates through the list pointing the last to the
//first
while(head != NULL) {
nextOne = head->Next();
head->Next() = marker;
marker = head;
head = nextOne;
}
//Setting the head back to the start again
head = marker;
}
};
One of those functions is supposed to reverse the list. The line "head->Next() = marker;" in the ReverseList function is causing a "lvalue required as left operand of assignment" error when compiling.
Any insight as to why this is occurring and how I can correct the problem?
Thank you in advance!
The return from the call to Next() is an rvalue. As you are in a class function, you don't need to call the Next function to get at the private next pointer, you can just use it directly.
head->next = marker;
Your Next() function returns a pointer, and you then do this:
head->Next() = marker;
You're changing the pointer to marker and not what it's pointing at. To solve this you need to dereference that pointer:
*head->Next() = marker;
your signature for next is:
Node *Next() {return next;}
This makes a copy of next pointer at return and hence it is treated as r-value and not l-value.
One way of overcoming this would be to use a pointer-to-pointer:.
Node **Next() {return &next;}
And then use it as:
int main()
{
Node* marker=new Node(89);
Node* nod=new Node(9);
*(nod->Next())= marker;
cout<<(nod->next)->data<<endl;
cout << "Hello World" << endl;
return 0;
}
This makes it more complicated to use.