I'm working on a class project and this piece of code won't let me delete an instance of a class without throwing a breakpoint error.
The class is Node, I'm trying to build a singly linked list for data structures and algorithms. I'll include the whole program, it isn't long, but the code in question that's causing the problem is in deleteMin(), the delete u.
#include <iostream>
using namespace std;
// we create a Node class.
class Node { // inside this class we hold two pieces of information.
int x; // the integer x, which is our data.
Node* next; // and the address of the next node.
public:
Node(int x0) : x(x0), next(NULL) { } // Here I've set up a constructor that sets x equal to the argument
// and defaults the next address to NULL.
bool add(int newValue); // Here follows our three required functions.
int deleteMin();
int size();
void printSSL(); // I also added a printSSL() function so that we can test and see what's going on.
};
//Originally I wanted to put these inside of the Node class, but then you'd end up with a unique head and tail for every Node.
//So instead I've left them outside. If you wanted to create multiple SSList's then you'd want to create an object out of these as well.
Node* head; // The first value in the our SLList.
Node* tail; // The last value in our SLList.
int n; // The number of elements in the list.
// I should mention here that head and tail are set equal to the first value in the SLList in the Main() function below.
// Here follows the actual implementation.
// I chose to try and simplify things by focusing on the add() function.
// If the add function organizes the information, and puts it into the SLList in order,
//then deleteMin() only has to pull the first value.
bool Node::add(int newValue) { // add() is a member function of Node and it takes in the newValue were adding to the list.
Node* u = new Node(newValue); // First thing we do is create a new Node using the argument value x. We pass this into a pointer, u.
if (newValue <= head->x) { // Next, we check to see if the new value is less than the head.
u->next = head; // if it is, then our job is done and we just make this new, smaller value, the new head.
head = u; // we do this by making the initial head equal to the next address in the new Node u.
n++; // Once we have the address saved, we make u into the new head and increment n.
return true; // There's no iteration in this case, so this if statement would be O(1).
}//O(1)
else { // If the new value is greater than the head, then we have to store it further back in the SLList.
Node* y = head; // This was the hardest part of the whole thing... I solved it by creating two Node pointers,
Node* z = head; // Both Node pointers are set equal to head, but this is mostly just to ensure that they aren't empty.
while ((newValue > y->x) && (y != tail)) { // Then I set a while loop that looks at whether the new value is less than the value in the head.
z = y; // The while loop continues, moving through the list of values, setting y equal to the next value,
y = y->next; // and using z to keep track of the former value.
} // The loop exits when we either a) hit the end of the SLList, y == tail, or when the new value is
if (y == tail) { // smaller than the next value, newValue < y->x. When the loop exits we have to deal with these two
y->next = u; // scenarios separately. If we reached the end of our list, then adding the new value is as simple as
tail = u; // setting y->next equal to u, then we make u into the new tail.
} // if we didn't reach the end of the list, then we have to set u inbetween z and y. This was really
else { // the only reason I needed z. I needed to be able to update the address of the previous Node, and
z->next = u; // I also needed to have the address of the next Node, this way I could slip u inbetween the two.
u->next = y; // Worst case scenario, this function runs through the entire SLList and then adds the value at the end.
} // I could have shaved off some time by asking if(newValue > tail->x) then run the z->next=u; and u->next=y; after
n++; // after that, but that throws an error becauset ail is a NULL pointer, which is bull#*#!
return true; // because I'm not dealing the tail->next, all I care about is tail->x which isn't NULL.
}//O(n) // But because this is an SSList and not a DLList I have no way of going to the n-2 element.
}//O(max(1, n)) // When that's done, we just increment n and leave the function.
// Considering that the worst case scenario, when x > tail->x, takes us through the whole SLList.
// I'm going to say that this add function is O(n).
int Node::deleteMin() { // The deleteMin() function starts by checking whether or not the
int x = head->x;
Node* u = head;
head = head->next;
delete u; // I have to figure out what the hells going on right here, why can't I delete this?
return x;
}
int Node::size() {
cout << n + 1 << endl;
return n + 1;
}
void Node::printSSL() {
Node* u = head;
cout << "Head:";
for (int i = 0; i <= n; i++) {
cout << i << ":(" << u->x << ", " << u->next << ") ";
u = u->next;
}
cout << " Tail" << endl;
}
int main()
{
Node one(1);
head = &one;
tail = &one;
one.printSSL();
one.deleteMin();
}
You declared an object of the type Node
Node one(1);
You may not apply the operator delete to a pointer to the object because the object was not allocated dynamically. It has automatic storage duration.
Pay attention to that it is a bad idea when functions depend on global variables. For example you will be unable to define two lists in your program.
What you need is to define a class named something like List the following way
class List
{
private:
Node *head = nullptr, *tail = nullptr;
public:
// special member functions and some other member functions;
void clear();
~List() { clear(); }
};
and to allocate nodes dynamically that will be inserted in the list.
The destructor and the function clear will delete all the allocated nodes in the list.
class Node also should be defined as a nested class of the class List.
For example the function clear can be defined the following way
#include <functional>
//...
void List::clear()
{
while ( head )
{
delete std::exchange( head, head->next );
}
tail = nullptr;
}
#include <iostream>
using namespace std;
class SLList { // SLList is the object that holds the entire list.
public: // The Node class lives inside the SLList class.
struct Node {
int data;
Node* next;
Node(int x0) : data(x0), next(NULL) {}
Node() : data(NULL), next(NULL) {}
};
Node* head;
Node* tail;
int n;
SLList() : n(0) {
Node* initial = new Node();
head = initial;
tail = initial;
cout << "You've created a new SSList" << endl;
}
bool add(int newValue);
int deleteMin();
int size();
void printSSL();
};
bool SLList::add(int newValue) { //
if (n == 0) {
head->data = newValue;
n++;
return true;
}
else {
Node* u = new Node(newValue);
if (newValue <= head->data) { //
u->next = head; //
head = u; //
n++; //
return true; //
}//O(1)
else { //
Node* y = head; //
Node* z = head; //
while ((newValue > y->data) && (y != tail)) { //
z = y; //
y = y->next; //
} //
if (y == tail && newValue > y->data) {
y->next = u; //
tail = u; //
} //
else { //
z->next = u; //
u->next = y; //
} //
n++; //
return true;
}
}//O(n) //
}//O(max(1, n)) //
int SLList::deleteMin() {
int x = head->data;
Node* u = head;
head = head->next;
delete u;
n--;
return x;
}//O(1)
int SLList::size() {
cout << n + 1 << endl;
return n + 1;
}//O(1)
void SLList::printSSL() {
Node* u = head;
cout << n << " Nodes|" << "Head:";
for (int i = 0; i < n; i++) {
cout << i << ":(" << u->data << ", " << u->next << ") ";
u = u->next;
}
cout << " Tail" << endl;
}//O(n)
int main() {
SLList* one = new SLList;
one->printSSL();
one->add(30);
one->printSSL();
one->add(20);
one->printSSL();
for (int i = 0; i < 7; i++) {
int x = rand() % 50;
one->add(x);
one->printSSL();
}
for (int i = 0; i < 9; i++) {
one->deleteMin();
one->printSSL();
}
}
I've been studying about dynamic allocated lists (the stuff we are discussing right now in class is pretty outdated tbh) and I can't seem to access the next node in a list. (I've just began learning this topic)
The problem is that the while loop that I'm using for going through the list never stops. I'm definitely missing something and I don't understand what.
struct node {
int info;
node* next;
};
int main()
{
node *p, *prim=NULL;
p = prim;
node* t;
t = new node;
p->next = t;
while (p != NULL)
{
cout << "test";
p = p -> next;
}
return 0;
}
Here is the code.
Why does my program not output anything and also tells me "it exited with code -1073741819" instead of 0?
Thanks.
////edit: I forgot to tell you that I've tried this way too
struct node {
int info;
node* next;
};
int main()
{
node *p, *prim=NULL;
p = prim;
node* t;
t = new node;
prim->next = t;
while (p != NULL)
{
cout << "test";
p = p -> next;
}
return 0;
}
Let's analyze your code:
node *p, *prim=NULL; // prim is NULL, p not yet initnialized
p = prim; // p now equal to NULL as well
node* t;
t = new node; // t is allocated
p->next = t; // NULL->next = t
So you're crashing on a null pointer when you try to dereference p->next for assignment.
It looks like you're trying to setup a basic linked list and loop through it. Your loop looks good, but you forgot the part where you actually setup the list!
That could look like:
struct node {
int info;
node* next;
//Add a quick constructor to make creating new nodes easy
node(int i) : info(i), next(nullptr) { }
};
int main()
{
//Start out with 3 itmes
// This list will look like:
// head -> 5 -> 3 -> 1
node *head = new node(5);
head->next = new node(3);
head->next->next = new node(1);
//Loop through the list and print each value
for(node *p = head; p; p = p->next) {
std::cout << p->info << std::endl;
}
//Don't forget to delete the memory you allocated to prevent a leak!
for(node *p = head; p;) {
node *temp = p->next;
delete p;
p = temp;
}
return 0;
}
See it run: https://ideone.com/WngD3b
I am issues with a homework assignment. We are working on binary trees and whenever I try to pass my head node to my insert() function the node is not being changed. This has lead me to believe that I am somehow not passing by reference, I just can't figure out where the mistake is, however. Thank you for any help in advance.
/*Linked List
**Code inspired by Linked List by Daniel Ross
**Code written by Collin Bardini
**Assignment 6
*/
#include <iostream>
using namespace std;
//Our node
struct node {
int data;
node* left; //lower
node* right; //greater
};
//function declarations
void insert(node * head, int);
void print_preorder(node * root);
void print_postorder(node * root);
void print_inorder(node * root);
int search(int data, node * root);
//main for testing the access functions
void main(void)
{
node* headA = 0;
node* headB = 0;
const size_t as = 7;
const size_t bs = 100;
int a[as] = {1,5,4,6,7,2,3};
int b[bs] = {118,119,158,166,163,123,108,116,117,184,165,137,141,111,138,122,109,194,143,183,178,173,139,
126,170,190,140,188,120,195,113,104,193,181,185,198,103,182,136,115,191,144,145,155,153,151,
112,129,199,135,146,157,176,159,196,121,105,131,154,107,110,175,187,134,132,179,133,102,172,
106,177,171,156,168,161,149,124,189,167,174,147,148,197,160,130,164,152,142,162,150,186,169,
127,114,192,180,101,125,128,100 };
for (int i = 0; i < as; i++)
insert(headA, a[i]);
for (int i = 0; i < bs; i++)
insert(headB, b[i]);
print_preorder(headA);
cout << "search 196: " << search(196, headB) << endl <<
"search 137: " << search(137, headB) << endl <<
"search 102: " << search(102, headB) << endl <<
"search 190: " << search(190, headB) << endl;
}
// creates a new node and inserts it in the correct location in the tree
void insert(node * head, int d)
{
//make a new node
node *p = new node;
p->right = 0;
p->left = 0;
p->data = d;
if (head == 0) //list is empty
head = p;
else //append to tail end
{
node* c1 = head;
node* c2 = head;
while (c1)
{
if (d > c1->data)
{
c2 = c1;
c1 = c1->right;
}
else
{
c2 = c1;
c1 = c1->left;
}
}
if (d > c2->data)
c2->right = p;
else
c2->left = p;
}
}
Short answer: see my answer to this identical question and use double pointers in the insert() function.
Regarding the "pass-by-reference" part of the question, well it depends on what exactly you mean by these words. You are passing the node by reference, true, but you're passing the pointer to the node by value. Remember that pointer is just another variable holding a non-negative integer value (overly simplified, but still true).
Long answer: the modifying functions should use either double pointers or references to pointers. The reason is that, in a function definition like void insert(node * head, int d) { /*...*/ }, the pointer itself is passed by value. That is, a temporary copy of the original pointer is created, and modified inside the function. The actual pointer remains unchanged. I.e., in these lines:
// definition
if (head == 0) //list is empty
head = p;
// client code
for (int i = 0; i < as; i++)
insert(headA, a[i]);
The temporary local variable head is modified, not the headA variable that you pass to the function. See the linked question where I posted a schematics of what happens with the pointer values in this situation.
You can change to e.g. double pointers like so:
void insert(node ** head, int d) {
// snip...
if (*head == 0) //list is empty
*head = p;
Or pass the pointer by reference.
Note: for read-only functions, such as print...(), you don't need to use a double pointer or any other pass-by-reference mechanism.
I didn't quite know how to describe the question -and whether there is any name for my error.
When i run the programme type some number e.g. 5 the tree.root->pocz is first 1 and later the weird number. Anyone know what's going on and how to repair it?
struct Node
{
int pocz;
int kon;
Node *left, *right, *up;
};
class AVL{
public:
Node *root;
void initiate(){
root = NULL;
}
bool insertNode(int poczPrz, int konPrz);
};
AVL tree;
//part of AVL insert function
bool AVL::insertNode(int poczPrz, int konPrz){
Node w;
w.pocz = poczPrz;
w.kon = konPrz;
Node *n = &w;
Node *x = tree.root;
Node *y, *z;
y = n->left = n->right = NULL;
while(x){
if(x->pocz == n->pocz){
delete n;
return false;
}
y = x;
x = (n->pocz < x->pocz) ? x->left : x->right;
}
if(!(n->up = y)){
cout << "We leave the function here\n";
tree.root = n;
return true;
}
if(n->pocz < y->pocz) y->left = n;
else y->right = n;
}
int main()
{
int n; cin >> n;
tree.initiate();
tree.insertNode(1,n);
cout <<"root->pocz: "<< tree.root->pocz <<endl; //prints 1
cout <<"root->pocz: "<< tree.root->pocz <<endl; //now prints sth like 2306050
return 0;
}
The main problem is that n points to w which is a local variable in the function insert. At the end of the function insert, w gets deleted automatically. And the pointer that is in the tree points to an empty location. At your first cout instruction, by chance, nothing did overwrite over the previous memory location of w. Therefore it prints 1. That memory location is then over written by something else (from the cout call) and therefore it prints garbage.
Now the solution, use Node *n = new Node; instead of setting it to &w.
In insertNode your w object has automatic storage and n is a pointer to it. In the call to that function, it will assign tree.root = n;. After the function returns the object is destroyed and the pointer tree.root is left dangling (points to deallocated memory). After that, dereferencing the dangling pointer such as tree.root->pocz will have undefined behaviour. You can fix that by allocating the Node dynamically.
This is simple adding nodes to linked list. I'm not able to figure out why the head pointer is being set to null with every call to add function.
//struct declaration of node
struct node {
int data;
node* next;
};
//adding node to the head pointer
void add_node(node* head, int d)
{
node* temp = new node;
temp->data = d;
temp->next = NULL;
node* tmp = head;
if (tmp != NULL) {
cout << "shal";
while (tmp->next != NULL)
tmp = tmp->next;
tmp->next = temp;
}
else {
//cout<<temp->data;
head = temp;
}
cout << "dh" << head->data;
}
int main()
{
node* head = NULL;
// calling the add function
add_node(head, 10);
// head is being taken as null here
add_node(head, 20);
}
Output:
dh10nulldh20null
Please help me in understanding where it went wrong.
I guess you didn't get what a pointer is.
void plus_one(int num) {
num += 1;
}
int main() {
int num = 42;
plus_one(num);
std::cout << num << std::endl;
}
Obviously, num is still 42. Why? Because in function plus_one you get num by copy.
When you call your add_node, you send a copy of your head pointer. Since it is a pointer, you can modify what is POINTED BY the pointer, NOT the pointer itself. What you do is the same thing as trying to get 43 with my example... It's not possible if you are getting a copy.
You need to pass the address of your pointer, so call your function as it : add_node(&head, 10); and write your prototype as it : void add_node(node** head,int d). You will have to modify your function to fit with your new node**.
Why does it work? Because you modify the content of the pointer which is POINTING TO you original pointer (which is POINTING TO your structure).