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.
Related
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 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 have doubts about the following test snippet. I use a Node pointer to point the node instance returned by function test2. Why the delete failed ?
Any comments would be appreciated. thanks!
struct Node
{
int a;
};
Node& test2(Node &n)
{
Node *p = new Node;
p->a = n.a + 5;
return *p;
}
Node* test3(Node &n)
{
Node *p = new Node;
p->a = n.a + 5;
return p;
}
int main()
{
Node m;
m.a = 12;
Node n = test2(m);
Node *x = test3(n);
cout << m.a << ";" << n.a << ";" << x->a << endl;
delete x; //OK
x = &n;
delete x; //Error
return 0;
}
When you write
Node n = test2(m);
n is not a reference to the Node created by test2. It is a copy of it. The Node created by test2 is leaked. You need:
Node& n = test2(m);
As an aside: I assume this is an exercise to understand references and pointers. For a real program, you would always want to write:
std::unique_ptr<Node> test4(const Node& n)
{
std::unique_ptr<Node> result{new Node};
result->a = n.a + 5;
return result;
}
or even better:
std::unique_ptr<Node> test4(const Node& n)
{
auto result = std::make_unique<Node>();
result->a = n.a + 5;
return result;
}
With either of these solutions, you don't need to bother about deleting the allocated Node - the compiler will do that for you when the unique_ptr in your calling code goes out of scope.
test2 returns a reference of a Node object that's copied (or moved) to n because n is not a reference.
This object now resides on the stack, calling delete on objects on the stack is illegal.
Why the delete failed ?
Here
x = &n;
delete x; //Error
you are assigning an address of a local variable
Node n = test2(m);
which can't (neither needs to) be handled by delete.
I have been trying to use pointer to pointer to perform action something similar to inorder traversal in tree. here is my code
struct node {
char c = '\0';
int freq = 0;
node *left = NULL;
node *right = NULL;
string code = "";
};
void appendones(node **n) {
if ((*n) == NULL)
;
else {
(*n)->code += "1";
appendones(&(*n)->left);
appendones(&(*n)->right);
}
}
void combinenodes(node *a, node *b, node **n) {
appendones(&a);
appendones(&b);
//(*n)=newNode('\0',a->freq+b->freq);
(*n)->c = '\0';
(*n)->freq = a->freq + b->freq;
(*n)->left = a;
(*n)->right = b;
}
int main() {
N = input();
priority_queue<node, vector<node *>, compareNodefreq> nodefreq; // function object
for (int i = 0; i < N; i++) {
char s;
int freq;
cin >> s >> freq;
node *n = newNode(s, freq);
nodefreq.push(n);
}
// printheap(nodefreq);
// perform combining nodes based on frequencies
while (nodefreq.size() > 1) {
node *a = nodefreq.top();
nodefreq.pop();
node *b = nodefreq.top();
nodefreq.pop();
node *n;
combinenodes(a, b, &n);
nodefreq.push(n);
}
}
I get segmentation fault in (*n)->code+="1"; for appendone().
I am not able to figure out the error. My understanding is that I am passing
the pointer by reference and performing the appendzero() and appendone(),
so I guess there is no error in that part. Also my a and b in
combinenodes() cannot be null because I am popping from the stack.
Could you help me figure out?
Oh, I see it. In main()'s while loop, n is pushed and used later, but is invalid because the node object itself is never allocated in combinenodes() (currently commented out). The pointer value, then, is undefined, but in this case, turning out to be non-zero, defeating the safety check.
EDIT: Is it possible to NOT use new? (do not dynamically allocating memory)
I think it is push that is wrong, but I don't know where, how, and why. here is the code:
struct Node {
string fileName;
Node *link;
};
int size(Node *&flist) {
int count = 0;
Node *tempPtr = flist;
while (tempPtr != 0) {
count += 1;
tempPtr->link = (tempPtr->link)->link;
}
return count;
}
Node* push(Node *&flist, string name) {
Node temp;
Node *tempPtr = &temp;
temp.fileName = name;
temp.link = flist;
cout << tempPtr->fileName << endl;
cout << (tempPtr->link)->fileName << endl;
return tempPtr;
}
int main( int argc, char *argv[] ) {
Node aNode;
Node *flist = &aNode;
flist->fileName = "a";
flist->link = NULL;
push(flist, "b");
int s = size(flist);
cout << "size: " << s << endl;
}
the output is
b
a
size: 0
Thank you.
In your size() function you are modifying the list in the loop. You don't want to modify tempPtr->link but rather just change tempPtr as you iterate. Changing tempPtr won't modify anything permanently. You should also avoid passing flist by reference here as there's no need to modify it. So:
int size(Node *flist) {
int count = 0;
Node *tempPtr = flist;
while (tempPtr != 0) {
count += 1;
tempPtr = tempPtr->link;
}
return count;
}
As for push(), the biggest problem is that you're allocating the new node as a local variable which means it'll be on the stack and will get destroyed when the function returns. To create a node that is more permanent you need to allocate it on the heap using the new operator. And again the '&' for flist is unnecessary:
Node* push(Node *flist, string name) {
Node *tempPtr = new Node;
tempPtr->fileName = name;
tempPtr->link = flist;
cout << tempPtr->fileName << endl;
cout << tempPtr->link->fileName << endl;
return tempPtr;
}
Note that the counterpart to new is delete. Since the new nodes are allocated on the heap they will not be destroyed automatically so you will need to manually delete them when you are done with the list. Your goal is to have one delete for every new, so if you new 5 nodes your code should delete 5 nodes when it cleans up. If you don't do this your program will run fine but it will have a small memory leak.
(Actually, when it exits all allocated memory is automatically freed. But it's a bad habit to allocate memory and never free it, in general, so you should pretend this automatic cleanup doesn't happen.)
Well, your size() function is a little overkill. You might try
int size(Node *flist) {
int count = 0;
Node *tempPtr = flist;
while (tempPtr) {
count += 1;
tempPtr=tempPtr->link;
}
return count;
}
I've removed an extraneous exit condition from the while statement that prevented calculation of the length of lists that have only one element.
The reason it's returning 0 in your version is that your while statement:
while ((tempPtr != 0) &&(tempPtr ->link != 0)) {
count += 1;
tempPtr->link = (tempPtr->link)->link;
}
never executes since your one node has a .link value of null (0). Try the modified version I provided above.
Oh, in the future, you might want to tag these sorts of posts as "homework." You'll get better responses.
You need to use new. Otherwise the variable temp is destroyed at the end of the push function. Later, if you try to access what that pointer pointed to, it will be GONE.