I am trying to implement a priority Queue by using a linked list in c++. However, when I run the program it triggers a breakpoint within "priorityQLinkedList::dequeue()" method. Can someone tell why this is the case and give me suggestions on how to fix it?
Code:
#include <iostream>
#include <cstring>
#include <iomanip>
using namespace std;
struct DAT
{
int id;
char fullname[50];
double savings;
};
struct NODE
{
DAT data;
NODE *N;
NODE *P;
NODE(const int i, const char *f, const double s)
{
data.id = i;
strcpy_s(data.fullname, f);
data.savings = s;
N = NULL;
P = NULL;
}
};
class priorityQLinkedList
{
private:
NODE *front;
NODE *back;
public:
priorityQLinkedList() { front = NULL; back = NULL; }
~priorityQLinkedList() { destroyList(); }
void enqueue(NODE *);
NODE* dequeue();
void destroyList();
};
void priorityQLinkedList::enqueue(NODE *n)
{
if (front == NULL) {
front = n;
back = n;
}
else {
NODE *temp = front;
if (n->data.id > temp->data.id)
{
front->P = n;
n->N = front;
front = n;
}
else
{
//search for the posistion for the new node.
while (n->data.id < temp->data.id)
{
if (temp->N == NULL) {
break;
}
temp = temp->N;
}
//New node id's smallest then all others
if (temp->N == NULL && n->data.id < temp->data.id)
{
back->N = n;
n->P = back;
back = n;
}
//New node id's is in the medium range.
else {
temp->P->N = n;
n->P = temp->P;
n->N = temp;
temp->P = n;
}
}
}
}
NODE* priorityQLinkedList::dequeue()
{
NODE *temp;
//no nodes
if (back == NULL) {
return NULL;
}
//there is only one node
else if (back->P == NULL) {
NODE *temp2 = back;
temp = temp2;
front = NULL;
back = NULL;
delete temp2;
return temp;
}
//there are more than one node
else {
NODE *temp2 = back;
temp = temp2;
back = back->P;
back->N = NULL;
delete temp2;
return temp;
}
}
void priorityQLinkedList::destroyList()
{
while (front != NULL) {
NODE *temp = front;
front = front->N;
delete temp;
}
}
void disp(NODE *m) {
if (m == NULL) {
cout << "\nQueue is Empty!!!" << endl;
}
else {
cout << "\nID No. : " << m->data.id;
cout << "\nFull Name : " << m->data.fullname;
cout << "\nSalary : " << setprecision(15) << m->data.savings << endl;
}
}
int main() {
priorityQLinkedList *Queue = new priorityQLinkedList();
NODE No1(101, "Qasim Imtiaz", 567000.0000);
NODE No2(102, "Hamad Ahmed", 360200.0000);
NODE No3(103, "Fahad Ahmed", 726000.0000);
NODE No4(104, "Usmaan Arif", 689000.0000);
Queue->enqueue(&No4);
Queue->enqueue(&No3);
Queue->enqueue(&No1);
Queue->enqueue(&No2);
disp(Queue->dequeue());
disp(Queue->dequeue());
disp(Queue->dequeue());
disp(Queue->dequeue());
disp(Queue->dequeue());
delete Queue;
return 0;
}
One problem which stands out in your dequeue() method is that you are calling delete on a NODE pointer, and then attempting to return this deleted pointer to the caller. This could cause an error either in dequeue() itself, or certainly in the caller who thinks he is getting back a pointer to an actual live NODE object.
One potential fix would be to create a copy of the NODE being dequeued. You would still remove the target from your list, but the caller would then be returned a valid pointer, which he could free later.
NODE* priorityQLinkedList::dequeue()
{
NODE *temp;
// no nodes
if (back == NULL) {
return NULL;
}
NODE *temp2 = back;
temp = new NODE(temp2->data.id, temp2->data.fullname, temp2->data.savings);
// there is only one node
else if (back->P == NULL) {
front = NULL;
back = NULL;
delete temp2;
return temp;
}
// there are more than one node
else {
back = back->P;
back->N = NULL;
delete temp2;
return temp;
}
}
You're deleting pointers in dequeue that priorityQLinkedList does not own, so you don't know if it is safe to delete them.
In this case, they are not since the node pointers passed to enqueue are addresses of local, stacked based variables and have not been allocated by new. (There's also the already mentioned problem of deleting a pointer then returning it, which is Undefined Behavior.)
The fix for the code as shown is to remove the calls to delete in dequeue. However, if changes are made so that the nodes passed to enqueue are dynamically allocated, you'll need to add something to handle that.
1.First change strcpy_s to strcpy is struct NODE.
2.Instead of Delete(temp2) use temp2--.
//no nodes
if (back == NULL) {
return NULL;
}
//there is only one node
else if (back->P == NULL) {
NODE *temp2 = back;
temp = temp2;
front = NULL;
back = NULL;
temp2--;
return temp;
}
//there are more than one node
else {
NODE *temp2 = back;
temp = temp2;
back = back->P;
back->N = NULL;
temp2--;
return temp;
}
I hope this will resolve the problem.
Related
I have a little problem which occurs after trying to execute function delete_all(). Any idea why Visual Studio is throwing me an error:
Invalid address specified to RtlValidateHeap, instruction __debugbreak() or something similar
Everything works perfect until I want to execute this function.
#include <iostream>
using namespace std;
struct node {
string name = "n1";
node* prev = NULL;
node* next = NULL;
};
node* add(node* first, string name) {
if (first == NULL) {
return NULL;
}
node* nowy = new node;
if (first->next == NULL) {
nowy->prev = first;
first->next = nowy;
}
else {
while (first->next != NULL) {
first = first->next;
}
nowy->prev = first;
first->next = nowy;
}
nowy->name = name;
return nowy;
}
void writeout(node* first) {
if (first == NULL) cout << "first = NULL";
while (first->next != NULL) {
cout << first->name;
cout << "\n";
first = first->next;
}
if (first->next == NULL) {
cout << first->name;
cout << "\n";
}
}
void delete_all(node* first) {
node* temp;
while (first != NULL) {
temp = first->next;
delete first;
first = temp;
}
}
int main()
{
node n1;
add(&n1, "n2");
add(&n1, "n3");
writeout(&n1);
delete_all(&n1);
}
You declared an object in main() with automatic storage duration as the first node of the list:
node n1;
You may not destroy it using the delete operator.
Using your approach of the list implementation, you could define the function delete_all() the following way:
void delete_all(node* first)
{
if ( first != nullptr )
{
while ( first->next != nullptr )
{
node *temp = first->next;
first->next = temp->next;
delete temp;
}
}
}
But, it will be much better if initially in main(), you declared a pointer to a node. In this case, you will need to update the functions.
Your implementation of delete_all() is fine, but you are passing it a pointer to a node instance that was not created with new, so delete'ing that node is undefined behavior. ALL of your node instances should be created dynamically, including the 1st node.
As such, your add() function should be updated to not blindly return without creating a new node instance if first is initially NULL. You should instead update the caller's node* pointer to point at the new node that was created.
Also, writout() has undefined behavior if first is NULL, because you are unconditionally accessing first->next whether first is NULL or not.
With that said, try something more like this instead:
#include <iostream>
using namespace std;
struct node {
string name = "n1";
node* prev = nullptr;
node* next = nullptr;
};
node* add(node* &first, string name) {
if (!first) {
first = new node{name};
return first;
}
else {
node *prev = first;
while (prev->next) {
prev = prev->next;
}
prev->next = new node{name, prev};
return prev->next;
}
}
/* alternatively:
node* add(node* &first, string name) {
node **nowy = &first, *prev = nullptr;
while (*nowy) {
prev = *nowy;
nowy = &(prev->next);
}
*nowy = new node{name, prev};
return *nowy;
}
*/
void writeout(node* first) {
if (!first) {
cout << "first = NULL";
}
else {
do {
cout << first->name;
first = first->next;
if (first) cout << '\n';
}
while (first);
}
}
void delete_all(node* first) {
node* temp;
while (first) {
temp = first->next;
delete first;
first = temp;
}
}
int main()
{
node* n1 = nullptr;
add(n1, "n2");
add(n1, "n3");
writeout(n1);
delete_all(n1);
}
Alternatively:
...
node* add(node* first, string name) {
if (!first) {
return new node{name};
}
else {
while (first->next) {
first = first->next;
}
first->next = new node{name, first};
return first->next;
}
}
/* alternatively
node* add(node* first, string name) {
// same as node** further above ...
}
*/
...
int main()
{
node* n1 = add(nullptr, "n2");
add(n1, "n3");
...
delete_all(n1);
}
so i want to implement a queue data structure in c++ and use some special methods like the delete_at() putting into consideration the constraints of the queue data structure, so I made it using the dequeue method and took all the data that are not equal to the index the user want to delete and stored in array in order to enqueue it all back in but without the index that the user want to delete, however nothing gets deleted , so here is the code :
#include <list>
using namespace std;
class Queue{
private:
struct node {
int data;
struct node *next;
};
struct node* front = NULL;
struct node* rear = NULL;
public:
void Enqueue(int d) {
struct node* tmp=new node;
if (rear == NULL) {
tmp->next = NULL;
tmp->data = d;
rear=tmp;
front = rear;
}
else {
rear->next = tmp;
tmp->data = d;
tmp->next = NULL;
rear = tmp;
}
}
int Dequeue() {
struct node* tmp = front;
int data=front->data;
if (front == NULL) {
return 0;
}
else{
if (tmp->next != NULL) {
tmp=front;
front = front->next;
delete tmp;
}
else {
tmp=front;
delete tmp;
front = NULL;
rear = NULL;
}
}
return data;
}
void Display() {
struct node* temp = front;
if (front == NULL) {
cout<<"Queue is empty"<<endl;
return;
}
while (temp != NULL) {
cout<<temp->data<<"\n";
temp = temp->next;
}
}
int Size() {
struct node* temp = front;
int cnt=0;
while (temp != NULL) {
cnt++;
temp = temp->next;
}
return cnt;
}
void Delete_at(int index){
int i=0;
int ar_size=Size();
int data_arr[ar_size-1];
if(index > Size()){
cout<<"\n"<<"Error: out of bounds !";
return;
}
while(i<ar_size){
if (i==(index-1)){
Dequeue();
}
else{
data_arr[i]=Dequeue();
}
i++;
}
i=0;
while(i<ar_size){
Enqueue(data_arr[i]);
i++;
}
}
};
int main() {
int i=0;
Queue q;
q.Enqueue(2);
q.Enqueue(6);
q.Enqueue(7);
q.Enqueue(1);
q.Enqueue(2);
q.Enqueue(4);
q.Delete_at(2);
q.Display();
return 0;
}
You have a two primary problems with your code generally, and Delete_at() cannot simply call Dequeue(). As a general note, your code contains duplicated expressions that can simply be consolidated. For example, Enqueue() can be written succinctly as:
void Enqueue(int d) {
struct node *tmp = new node;
tmp->next = nullptr;
tmp->data = d;
if (rear == nullptr) {
front = rear = tmp;
size = 1;
}
else {
rear->next = tmp;
rear = tmp;
size += 1;
}
}
Your Dequeue() function will segfault checking front->data BEFORE checking if front == nullptr. You must check before you dereference, e.g.
int Dequeue() {
struct node *tmp = front;
int data;
if (front == nullptr) { /* (must check before dereference (front->data) */
return 0;
}
data = front->data;
size -= 1;
if (tmp->next != nullptr) {
front = front->next;
}
else {
front = nullptr;
rear = nullptr;
}
delete tmp;
return data;
}
Your Delete_at() function must remove the node at a specific index. This requires that you maintain your ->next links throughout your list, updating the prev->next before the deleted node to point to the node after the one you are deleting. You do that by iterating with both the address of the node and a pointer to node. When you reach the index to remove, you simply replace what is currently at the address of that node with the next node and delete the current, see: Linus on Understanding Pointers
void Delete_at (size_t index) {
struct node *pnode = front, /* pointer to node */
**ppnode = &front; /* address of node */
if (index >= Size()) { /* validate with >= Size() */
std::cerr << '\n' << "Error: out of bounds !";
return;
}
while (index--) { /* loop index times */
ppnode = &pnode->next; /* address of next node */
pnode = pnode->next; /* pointer to next node */
}
*ppnode = pnode->next; /* replace struct at address with next */
delete pnode; /* delete removed node */
size -= 1;
}
Your Size() function simply reduces to a "getter" function:
size_t Size() {
return size;
}
Updating your example a bit and being mindful of Why is “using namespace std;” considered bad practice? your full code could now be:
#include <list>
#include <iostream>
class Queue{
private:
struct node {
int data;
struct node *next;
};
struct node *front = nullptr;
struct node *rear = nullptr;
size_t size;
public:
void Enqueue(int d) {
struct node *tmp = new node;
tmp->next = nullptr;
tmp->data = d;
if (rear == nullptr) {
front = rear = tmp;
size = 1;
}
else {
rear->next = tmp;
rear = tmp;
size += 1;
}
}
int Dequeue() {
struct node *tmp = front;
int data;
if (front == nullptr) { /* (must check before dereference (front->data) */
return 0;
}
data = front->data;
size -= 1;
if (tmp->next != nullptr) {
front = front->next;
}
else {
front = nullptr;
rear = nullptr;
}
delete tmp;
return data;
}
void Display() {
struct node *temp = front;
if (front == nullptr) {
std::cout << "Queue is empty" << '\n';
return;
}
while (temp != nullptr) {
std::cout << temp->data << '\n';
temp = temp->next;
}
}
size_t Size() {
return size;
}
void Delete_at (size_t index) {
struct node *pnode = front, /* pointer to node */
**ppnode = &front; /* address of node */
if (index >= Size()) { /* validate with >= Size() */
std::cerr << '\n' << "Error: out of bounds !";
return;
}
while (index--) { /* loop index times */
ppnode = &pnode->next; /* address of next node */
pnode = pnode->next; /* pointer to next node */
}
*ppnode = pnode->next; /* replace struct at address with next */
delete pnode; /* delete removed node */
size -= 1;
}
};
int main() {
Queue q;
q.Enqueue(2);
q.Enqueue(6);
q.Enqueue(7);
q.Enqueue(1);
q.Enqueue(2);
q.Enqueue(4);
q.Display();
std::cout << "\nq.Delete_at(2)\n\n";
q.Delete_at(2);
q.Display();
}
Example Use/Output
$ ./bin/queue_delete_at
2
6
7
1
2
4
q.Delete_at(2)
2
6
1
2
4
Look things over and let me know if you have further questions.
Edit With Additional Constraints From Comments
Per you comments, you have constraints of only being able to use Dequeue() and Enqueue() in Delete_at() and no pointers, etc... You can do that, but understand it will be horribly inefficient compared to simply removing the node at the index. You will essentially have to save (Dequeue()) your entire queue data in an allocated block of memory, omitting the index to remove. You will then need to iterate over all saved values calling Enqueue() to repopulated your list.
You can do that as:
void Delete_at (size_t index) {
if (index >= Size()) { /* validate with >= Size() */
std::cerr << '\n' << "Error: out of bounds !";
return;
}
size_t nelem = Size();
int *arr = new int [nelem],
n = 0;
for (size_t i = 0; i < nelem; i++) {
int tmp = Dequeue();
if (i != index && tmp)
arr[n++] = tmp;
}
for (size_t i = 0; i < (size_t)n; i++)
Enqueue (arr[i]);
delete[] arr;
}
(same output)
For a less readable more C++'ized presentation, you can replace the first loop with:
for (int i = 0, j = Dequeue(); j; i++, j = Dequeue())
if (static_cast<size_t>(i) != index)
arr[n++] = j;
It would be nice to have utilized at least a separate list pointer, so you could build the new list while simultaneously deleting the old, but your class/struct isn't setup to use additional pointers. So you are basically left with buffering all values except the index to remove and then recreating your queue.
I'm learning C++, I try to implement simple singly linked list but the delete node part fails. I could not comprehend why this basic delete_node part is failing. It seems prev->set_next line in delete_node method does not working correctly. I tried to debug it too but failed to spot the error.
using namespace std; //ignore it for simplicity
class Node {
int data;
Node *next;
public:
Node() {}
void set_data(int a_data)
{
data = a_data;
}
void set_next(Node *a_next)
{
next = a_next;
}
int get_data()
{
return data;
}
Node* get_next()
{
return next;
}
};
class List {
Node *head;
public:
List()
{
head = NULL;
}
void print_list();
void append_node(int data);
void delete_node(int data);
};
void List::print_list()
{
Node *temp = head;
if(temp == NULL)
{
cout << "empty" << endl;
return;
}
if(temp->get_next() == NULL)
{
cout << temp->get_data() << "--->";
cout << "NULL" << endl;
}
else
{
do
{
cout << temp->get_data() << "+++>";
temp = temp->get_next();
} while(temp != NULL);
cout << "NULL" << endl;
}
}
void List::append_node(int data)
{
Node *new_node = new Node();
new_node->set_data(data);
new_node->set_next(NULL);
Node *temp = head;
if(temp != NULL)
{
while(temp->get_next()!=NULL)
{
temp = temp->get_next();
}
temp->set_next(new_node);
}
else
{
head = new_node;
}
}
void List::delete_node(int data)
{
Node *temp = head;
if(temp == NULL)
{
return;
}
else
{
Node *prev = NULL;
do
{
prev = temp;
if(temp->get_data() == data)
{
prev->set_next(temp->get_next());
delete temp;
break;
}
temp = temp->get_next();
} while(temp!=NULL);
}
}
int main()
{
List list;
list.append_node(10);
list.append_node(20);
list.append_node(30);
list.append_node(40);
list.append_node(50);
list.append_node(60);
list.delete_node(30); //
list.print_list();
return 0;
}
valgrind gives me following error.
==22232== Invalid read of size 8
==22232== at 0x400D38: Node::get_next() (20_1.cpp:25)
==22232== by 0x400A5E: List::print_list() (20_1.cpp:62)
==22232== by 0x400C6C: main (20_1.cpp:127)
==22232== Address 0x5abdd28 is 8 bytes inside a block of size 16 free'd
==22232== at 0x4C2F24B: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==22232== by 0x400BA8: List::delete_node(int) (20
Lets take a closer look at these lines from the List::delete_node function
prev = temp;
if(temp->get_data() == data)
{
prev->set_next(temp->get_next());
delete temp;
break;
}
The first one make prev point to the very same node that temp is pointing to. After this prev == temp is true.
So when you do
prev->set_next(temp->get_next());
it is the same as
temp->set_next(temp->get_next());
That is, you make temp->next point to temp->next which doesn't change it at all. You never unlink the node from the list, but you do delete it. That makes your printing of the list invalid, as you will dereference a deleted node.
As a simple solution, you could do something like this:
if (head->get_data() == data)
{
// Special case: Head node is the one we want to delete
Node* old_head = head;
// Make the head be the second node in the list, if any
head = head->get_next();
// Delete the old head
delete old_head;
}
else
{
// We know it's not the head node of the list, use the "next" to find it
for (Node* node = head; node->get_next() != 0; node = node->get_next())
{
if (node->get_next()->get_data() == data)
{
// It's the "next" node we want to remove
Node* old_next = node->get_next();
// Unlink the node
node->set_next(node->get_next()->get_next());
delete old_next;
break;
}
}
}
The problem is that at the beginning of your do / while loop pointers temp and prev point to the same Node. Hence, you re-point the node, and then delete it right away.
A better approach is to not use prev at all. Get next, see if its data matches the one being deleted. If it does, "bypass" and delete next. Otherwise, move on to the next node until you hit NULL:
void List::delete_node(int data) {
if(head == NULL) {
return;
}
if (head->get_data() == data) {
Node *toDelete = head;
head = head->get_next();
delete toDelete;
return;
}
Node *temp = head;
for ( ; ; ) {
Node *next = temp->get_next();
if (next == null) {
break;
}
if (next->get_data() == data) {
temp->set_next(next->get_next());
delete next;
break;
}
temp = temp->get_next();
}
}
The exact working solution is
void List::delete_node(int data)
{
Node *temp = head;
Node *prev = NULL;
//first check whether its a parent element or not
if(temp && temp->get_data() == data){
head = head->get_next();
delete temp;
}
else{
while (temp){
if (temp->get_data() == data){
if (prev)
prev->set_next(temp->get_next());
delete temp;
return;
}
prev = temp;
temp = temp->get_next();
}
}
}
This even works for deleting head node
I see a number of problems with your code.
Your Node constructors is not initializing any of the Node members.
Your List class is missing a destructor to free any allocated nodes.
Your print_list() and append_node() implementations are a little more verbose than they need to be.
But, most importantly, regarding your particular question, your list's delete_node() method is not managing its prev variable correctly. prev is always pointing at the current node that is being looked at, not at the previous node that was already looked at. So you are not actually updating your links correctly when removing a node. You are also not updating the list's head member if the node being removed is the head node.
Try something more like this instead:
class Node;
class List {
Node *head;
public:
List();
~List();
void print_list();
void append_node(int data);
void delete_node(int data);
};
class Node {
int data;
Node *next;
public:
Node(int a_data = 0, Node *a_next = NULL);
void set_data(int a_data);
void set_next(Node *a_next);
int get_data();
Node* get_next();
friend class List;
};
Node::Node(int a_data, Node *a_next)
: data(a_data), next(a_next)
{
}
void Node::set_data(int a_data)
{
data = a_data;
}
void Node::set_next(Node *a_next)
{
next = a_next;
}
int Node::get_data()
{
return data;
}
Node* Node::get_next()
{
return next;
}
List::List()
: head(NULL)
{
}
List::~List()
{
Node *temp = head;
while (temp)
{
Node *next = temp->get_next();
delete temp;
temp = next;
}
}
void List::print_list()
{
Node *temp = head;
if (!temp)
{
cout << "empty" << endl;
return;
}
do
{
cout << temp->get_data();
temp = temp->get_next();
if (!temp) break;
cout << "+++>";
}
while (true);
cout << "--->NULL" << endl;
}
void List::append_node(int data)
{
Node **temp = &head;
while (*temp) temp = &((*temp)->next);
*temp = new Node(data);
}
void List::delete_node(int data)
{
Node *temp = head;
Node *prev = NULL;
while (temp)
{
if (temp->get_data() == data)
{
if (prev)
prev->set_next(temp->get_next());
if (temp == head)
head = temp->get_next();
delete temp;
return;
}
prev = temp;
temp = temp->get_next();
}
}
int main()
{
List list;
list.append_node(10);
list.append_node(20);
list.append_node(30);
list.append_node(40);
list.append_node(50);
list.append_node(60);
list.delete_node(30); //
list.print_list();
return 0;
}
Im getting a segmentation fault when i try to push elements into the queue, im not an expert working with queues so i dont recognize where the problem is.
I have been searching for the solution to this problem and even though people get similar problems i didnt help me fix my problem.
Here is the code:
(I used the debug option in Dev-c ++ 5.9.2 and it told me the line "temp->link = NULL;" is causing the problem but i have no idea how to fix it)
#include <iostream>
using namespace std;
struct Node {
int data;
Node* link;
};
class Queue {
public:
Queue();
~Queue();
void pushBack(int d);
bool popFront();
bool isEmpty();
void displayQueue();
private:
Node* back;
Node* front;
};
Queue::Queue() {
back = NULL;
front = NULL;
}
Queue::~Queue() {
while (!isEmpty()) {
popFront();
}
}
void Queue::pushBack(int d) {
Node* temp;
if (temp == NULL) {
return;
} else {
temp->link = NULL; <========== This is where is get the error
if (back == NULL) {
back = temp;
front = temp;
} else {
front->link = temp; <===== here too
front = temp;
}
}
}
bool Queue::popFront() {
if (front == NULL) {
return false;
} else {
Node* removeNode;
removeNode = front;
if (back == front) {
back = NULL;
front = NULL;
} else {
Node* previousFront = back;
while (previousFront->link != front) {
previousFront = previousFront->link;
}
front = previousFront;
front->link = NULL;
}
delete removeNode;
return true;
}
}
bool Queue::isEmpty() {
return (back == NULL);
}
void Queue::displayQueue() {
if (isEmpty()) {
cout << "Queue is empty!" << endl;
} else {
Node *current;
current = back;
cout << endl << "-- BACK -- ";
while (current != NULL) {
cout << current->data << " ";
current = current->link;
}
cout << "-- FRONT --" << endl << endl;
}
}
int main(){
Queue q;
q.displayQueue();
q.pushBack(20);
q.pushBack(30);
q.displayQueue();
q.pushBack(40);
q.pushBack(12);
q.displayQueue();
q.popFront();
q.displayQueue();
return 0;
}
You have to know that when you add a new
node to the list you constructed, you need to allocate a dynamic
location for the new node and then add it to the list -queue-;
second thing : when the back is pointing already at some node in the link
you need to make the new node points at the node the back was pointing at,
then make the back pointer points at the new node .
the new function (pushBack) bacomes :
void Queue::pushBack ( int d ) {
Node* temp = new Node;
temp->data = d;
temp->link = NULL;
if (back == NULL) {
back = temp;
front = temp;
}
else {
temp->link = back;
back = temp;
}
}
You are creating a pointer to a node, but you have not created the node yet. (what everyone else has said)
change
Node* temp; - stack memory
To
Node *temp = new Node() - heap memory
im not an expert working with queues so i dont recognize where the problem is
Note that the problem has nothing to do with queues: The problem is understanding how the language works.
As Thornkey pointed out, you have a temp var in your pushBack function. It's a pointer, but it points to random data until you tell what to point at. When you follow the pointer, it could go anywhere and get a segfault or break some other part of your program.
I am trying to build my own implementation of a linked list in C++. My code is compiling but apparently there is some issue with my pointers referring to invalid memory addresses.
Here is my implementation:
#include <iostream>
#include <string>
using namespace std;
class Node
{
private:
string _car;
Node* nextNode;
public:
void setCar(string car)
{
_car = car;
}
string getCar()
{
return _car;
}
void setNextNode(Node* node)
{
nextNode = node;
}
Node* getNextNode()
{
return nextNode;
}
};
Node* findLast(Node* node)
{
Node* nodeOut = NULL;
while (node->getNextNode() != NULL)
{
nodeOut = node->getNextNode();
}
return nodeOut;
}
string toString(Node* node)
{
string output = "";
while (node->getNextNode() != NULL)
{
output += node->getCar() + " ";
node = node->getNextNode();
}
return output;
}
int main()
{
char xit;
//ser head node to NULL
Node* headNode = NULL;
//create node 1
Node* node1 = new Node();
node1->setCar("Mercedes");
//create node 2
Node* node2 = new Node();
node2->setCar("BMW");
//set node links
headNode->setNextNode(node1);
node1->setNextNode(node1);
node2->setNextNode(node2);
headNode = node1;
Node* lastNode = findLast(headNode);
lastNode->setNextNode(NULL);
cout << toString(headNode) << endl;
//pause console
cin >> xit;
}
You need to relook at your code.
headNode = node1;
This assignment should be done before accesing any member function of the instance headNode.
Intially you have assigned NULL to this pointer.
After creating node1 you are setting to headNode that is invalid instance. This is the cause of crash.
Be ensure with your objective and then try to implement do some rough work on paper , make some diagram that way you would be more clear that what you are exactly trying to achive.
why setNextNode ??? i don't undeerstand what you wanted to achieve. be clear first.
As per my undertanding this code should be implemented like below..
#include <iostream>
#include <string>
using namespace std;
class Node
{
private:
string _car;
Node* nextNode;
public:
void setCar(string car)
{
_car = car;
}
string getCar()
{
return _car;
}
void setNextNode(Node* node)
{
nextNode = node;
}
Node* getNextNode()
{
return nextNode;
}
};
Node* findLast(Node* node)
{
Node* nodeOut = node->getNextNode();
while ( nodeOut->getNextNode()!= NULL)
{
nodeOut = nodeOut->getNextNode();
}
return nodeOut;
}
string toString(Node* node)
{
string output = "";
while (node != NULL)
{
output += node->getCar() + " ";
node = node->getNextNode();
}
return output;
}
int main()
{
char xit;
//ser head node to NULL
Node* headNode = NULL;
//create node 1
Node* node1 = new Node();
node1->setCar("Mercedes");
node1->setNextNode(NULL);//Make null to each next node pointer
headNode = node1; //assign the node1 as headNode
//create node 2
Node* node2 = new Node();
node2->setCar("BMW");
node2->setNextNode(NULL);
//set node links
node1->setNextNode(node2);
Node* lastNode = findLast(headNode);
lastNode->setNextNode(NULL);
cout << toString(headNode) << endl;
//pause console
cin >> xit;
}
Hope it would be useful for the beginner who implement ing the linklist in c++.
Reread this:
node1->setNextNode(node1);
node2->setNextNode(node2);
...and think about what you're doing here.
If you're going to write linked-list code, I'd advise at least looking at the interface for std::list. Right now, you're interface is at such a low level that you'd be at least as well off just manipulating pointers directly.
The cause of your actual error is:
headNode->setNextNode(node1);
headNode is still set to NULL, thus you're dereferencing a NULL pointer. As noted by Jerry, you're also calling having nodes point to themselves, which is not what you want.
It would be cleaner if you took the car as a constructor parameter.
When you allocate a new Node, the pointer nextNode is not initialized, it's just random junk. You will need to explicitly set it to NULL (probably in a constructor for Node).
Also, I assume you know that the standard C++ library has a linked list built in and you're just doing this for learning ;-)
Thanks for all the suggestions, here is my final code after major cleanup:
// LinkedListProject.cpp : main project file.
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace System;
using namespace std;
class Node
{
public:
Node()
:_car(""), _nextNode(NULL)
{
}
void SetCar(string car)
{
_car = car;
}
string GetCar()
{
return _car;
}
void SetNextNode(Node *node)
{
_nextNode = node;
}
Node * GetNextNode()
{
return _nextNode;
}
private:
string _car;
Node *_nextNode;
};
string GetData();
Node * AddNode(Node *firstNode, Node *newNode);
Node * DeleteNode(Node *firstNode, string nodeData);
void PrintNodes(Node *firstNode);
int main(int argc, char *argv[])
{
string command = "";
string data = "";
Node *firstNode = NULL;
do
{
cout << "Enter command: ";
cin >> command;
if(command == "add")
{
data = GetData();
Node *newNode = new Node();
newNode->SetCar(data);
firstNode = AddNode(firstNode, newNode);
}
else if(command == "delete")
{
data = GetData();
firstNode = DeleteNode(firstNode, data);
}
else if(command == "print")
{
PrintNodes(firstNode);
}
} while(command != "stop");
return 0;
}
string GetData()
{
string data = "";
cout << "Enter data: ";
cin >> data;
return data;
}
Node * AddNode(Node *firstNode, Node *newNode)
{
//add new node to front of queue
newNode->SetNextNode(firstNode);
firstNode = newNode;
return firstNode;
}
Node * DeleteNode(Node *firstNode, string nodeData)
{
Node *currentNode = firstNode;
Node *nodeToDelete = NULL;
if (firstNode != NULL)
{
//check first node
if(firstNode->GetCar() == nodeData)
{
nodeToDelete = firstNode;
firstNode = firstNode->GetNextNode();
}
else //check other nodes
{
while (currentNode->GetNextNode() != NULL &&
currentNode->GetNextNode()->GetCar() != nodeData)
{
currentNode = currentNode->GetNextNode();
}
if (currentNode->GetNextNode() != NULL &&
currentNode->GetNextNode()->GetCar() == nodeData)
{
nodeToDelete = currentNode->GetNextNode();
currentNode->SetNextNode(currentNode->GetNextNode()->GetNextNode());
}
}
if(nodeToDelete != NULL)
{
delete nodeToDelete;
}
}
return firstNode;
}
void PrintNodes(Node *firstNode)
{
Node *currentNode = firstNode;
while(currentNode != NULL)
{
cout << currentNode->GetCar() << endl;
currentNode = currentNode->GetNextNode();
}
}