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)
Related
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.
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);
I created a simple dynamic linked list implementation in C++ which has a head node of 42, and after which, prompts the user if he/she wants additional numbers to add to the list.
#include <iostream>
using namespace std;
struct Node
{
int x;
Node *next;
};
int main(int argc, char** argv)
{
char choice;
Node *start = new Node;
start->next = NULL;
start->x = 42;
Node *traverser = start;
while (1) {
cout << "Add item to the list (Y/N)? ";
cin >> choice;
if (choice == 'Y') {
traverser->next = new Node;
traverser = traverser->next;
traverser->next = NULL;
cout << "New item: ";
cin >> traverser->x;
}
else {
cout << "Linked List:\n";
Node *p;
for (p = start; p != NULL; p = p->next) {
cout << p->x << endl; //QUESTION HERE!
}
cout << "\nProgram dismissed.";
exit(0);
}
}
}
Now the question, as indicated in the code block, lies on the pointer *p. The head of my linked list is named start, while the pointer that traverses and adds items to the list is named traverser. Why the heck is *p able to print all that's in the list when it is only assigned to the head
p = start
and not to the body of the list. I would've understood that this works for printing
cout << "Linked List:\n";
for (traverser = start; traverser != NULL; traverser = traverser->next) {
cout << traverser->x << endl;
}
But *p being able to print the whole list confused me, a lot!
Please help.
*p is able to print the whole list, because *p (initially) points to the start of the list. After the start of the list, comes the body of the list, that you linked with
if (choice == 'Y') {
traverser->next = new Node;
traverser = traverser->next;
traverser->next = NULL;
cout << "New item: ";
cin >> traverser->x;
}
Understand here, that initially traverser and start both manipulate the same object. To put it in layman's terms, when you're using pointers, you're not cloning values, you're cloning instructions on how to access the values. Perhaps this was the source of your confusion?
So, the Node* start points to a node. Node* traverse points to the same node, as you declared Node *traverser = start; You could manipulate the value of the node in question via traverse->x or start->x, and get the exact same result.
p is just a pointer variable, like any other variable it can have different values , but it points to addresses.
p = start
p starts pointing toward your first node.
p = p->next
it starts pointing towards next node.
Where are you confused ?
traverser does not contain the body of the list. startdoes.
Let's review the contents of your program:
Node *start = new Node;
start will always point to the node created here. start is always the beginning of the list.
From this node you can travel through the entire list using the nodes next member.
Node *traverser = start;
traverser is initially the same node as the start node. traverser indicates the end of the list. You can't use traverser to travel through the list. The reason traverser is used is that it simplifies the insertion of a new node at the end of the list.
The last statement is shown by the statements
traverser->next = new Node;
traverser = traverser->next;
traverser->next = 0;
The last statement tells us that we can't follow the traverser node anywhere. This is the end of the list.
So startis the entire list, start->x is the first value in the list. start->next is a pointer to the next element in the list.
Now, we don't want to corrupt the startof the list. So let's make a copy of the pointer to the first element, and call that copy p. Use p to look through the list. p is only useful for this small section of the code, whereas start and traverser is useful for the entire program.
Node* p = start;
for (; p != NULL; p = p->next) {
cout << p->x << endl;
}
The last element printed will be the same element as traverserpoints to.
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.
Here's the reference code:
#include <iostream>
using namespace std;
class linkedList {
struct listNode{ //a node of a list
int value;
struct listNode *next;
};
listNode *head;
public:
linkedList(){
cout << "hello1\n";
head = NULL;
};
linkedList(listNode* a){
cout << "hello2\n";
head = a;
};
~linkedList();
listNode* getHead() {return head;}
void appendNode(int);
//inline Search function due to unable to function outside of class definition
listNode* rangeSearch(int a, int b){
//listNode to search
listNode *search = head;
//listNode* toReturn = new listNode;
//listNode to return list of values that are found within range
linkedList *found = new linkedList;
while(search){
//if the current value is within range, then add to list
if(search->value >= a && search->value <= b){
//append searched value onto found
found->appendNode(search->value);
//after appending, go to next value
}
search = search->next;
}
return found->getHead();
}
void display();
};
int main()
{
cout << "Programmer : n\n";
cout << "Description : \n";
linkedList* list = new linkedList;
int x = 12;
//values to search
int s1 = 10, s2 = 14;
// adds 2 to each number on list for 5 times
for(int i = 0; i < 5; i++){
list->appendNode(x);
x += 2;
}
//create something to hold pointer of found to be deleted when done using
//print list
cout << "Original set of numbers in linked list: ";
list->display();
cout << "\nThe following are the values withing ranges: " << s1 << " and " << s2 << ":\n";
//EDITED:
//list->rangeSearch(s1,s2);
linkedList foundList(list->rangeSearch(s1,s2));
foundList.display();
//End of edit 6:40PM 7/18/13
cout << "\nHere are the original set of numbers in linked list (again): ";
list->display();
delete list;
return 0;
}
void linkedList::appendNode(int newValue)
{
listNode *newNode = new listNode(); // To point to a new node
listNode *nodePtr; // To move through the list
// Allocate a new node and store newValue there.
newNode->value = newValue;
newNode->next = 0;
// If there are no nodes in the list
// make newNode the first node.
if (!head)
head = newNode;
else // Otherwise, insert newNode at end.
{
// Initialize nodePtr to head of list.
nodePtr = head;
// Find the last node in the list.
while (nodePtr->next)
nodePtr = nodePtr->next;
// Insert newNode as the last node.
nodePtr->next = newNode;
}
}
void linkedList::display() {
for(listNode* p = head; p != NULL; p = p->next)
cout << p->value << ' ';
}
linkedList::~linkedList()
{
cout << "\ndestructor called";
listNode *nodePtr; // To traverse the list
listNode *nextNode; // To point to the next node
// Position nodePtr at the head of the list.
nodePtr = head;
// While nodePtr is not at the end of the list...
while (nodePtr != NULL)
{
// Save a pointer to the next node.
nextNode = nodePtr->next;
// Delete the current node.
delete nodePtr;
// Position nodePtr at the next node.
nodePtr = nextNode;
}
}
So a couple of questions here. First, why is it when I try to put the rangeSearch member function outside of the class definition, the compiler gives an error saying listNode* type is not recognized?
Second, this has to do with destructors. In this program, 2 instances (list & found list) were created but only 1 destructor was called. Can someone explain why? My intuition tells me that the dynamically allocated pointer to linkedList object did not get destructed. However, I don't know why. The reason I had to use dynamically allocated memory is primarily because I want to pass the pointer back to the main function. If I don't, when rangeSearch exits, the pointer will be passed back to main but whatever list the pointer had would be deconstructed after
return ptr; (assume ptr is a pointer to a linkedList declared in rangeSearch)
which will cause my program to crash because, now the address has nothing in it and I'm trying to call... nothing.
Well, as usual I would appreciate whoever the great Samaritan out there who would be more than willing to educate me more about this.
First, you are having an issue with scoping. In C++, the curly braces define a new scope, so you are defining listNode inside the class linkedlist. If you want to access it, you'd have to use the scoping operator as such linkedlist::listNode
I don't entirely understand your second question. I only see one call to delete, so why do you think two destructors will be called? The destructors are only called when you call delete, so unless you specify that you want to destroy it, it's still going to be there.
Although I don't entirely understand your question, I see that you returned a pointer to the head in rangeSearch, but you don't assign it to anything. What this means is that you will have a memory leak; you allocated memory for the found, but then don't do anything with it. Actually since you only return the head, you still wouldn't be able to delete it if you did assign something to it, because you wouldn't have access to linked list itself.
linkNode is nested inside of linkedList. Move listNode outside of the linkedList class, and you won't get the first error. Or you can use it's full declaration, linkedList::listNode. Also, if you leave linkNode nested, you will have to make it public.
In main, you can just say
linkedList list;
instead of
linkedList* list = new linkedList;
rangeSearch() is returning a value, but that value is never being assigned to anything in main(). rangeSearch() is allocating a linkedList, but it never gets deleted.