for some reason my nodes don't seem to be deleting. it looks as though it traverses to the end ok but after the node is "deleted" it still has the data in it. i've also tried
free(bNode) and bNode = NULL instead of delete bNode but they all give the same result.
The cout and display functions were just put in when I was trying to debug. I just don't understand why its not working, i hope i'm not missing something simple.
struct
Book{
char title [50];
char url [75];
Book *left;
Book *right;
};
void deleteAllBooks (Book *bNode){
if(bNode==NULL) return;
if(bNode->left !=NULL){
cout << endl << "deleting left" << endl;
deleteAllBooks(bNode->left);
}
if(bNode->right !=NULL){
cout << endl << "deleting right" << endl;
deleteAllBooks(bNode->right);
}
cout << endl << "deleting node " << bNode->title << endl;
delete bNode;
displayBookTree(bNode);
}
void displayBookTree(Book *bNode){
if(bNode==NULL){
cout << "No books" << endl;
return;
}
if(bNode->left !=NULL){
displayBookTree(bNode->left);
}
if(bNode->right !=NULL){
displayBookTree(bNode->right);
}
cout <<"Title: " << bNode->title << endl;
cout <<"URL: " << bNode->url <<endl;
}
"Use 0. The "NULL" macro is not type-safe; if you feel that you must
use "null", make it a const int instead of the C-style "#define". Also
see "The C++ Programming Language" for Stroustrup's argument against
the usage of "NULL"."
I would try to change:
if (bNode==NULL) { ... }
with
if (!bNode) { ... }
And
if (bNode->left !=NULL) { ... }
if (bNode->right !=NULL) { ... }
with
if (bNode->left) { ... }
if (bNode->right) { ... }
And then take a look to this answer on how correctly delete a Struct!
Easiest solution:
struct Book{
std::string title;
std::string url;
std::unique_ptr<Book> left;
std::unique_ptr<Book> right;
};
void deleteAllBooks (std::unique_ptr<Book> bNode)
{
// No code necessary. Literally. But usually you wouldn't even
// bother with this function, the default Book::~Book is fine.
}
Your solution is correct, but your observations are wrong. When you delete an object, the destructor will be executed for that object. In your case, this destructor has no visible side effect, because all your data members are plain old data types that do not have a destructor on there own. Using an object after it was deleted, invokes undefined behavior and your observation is one possible incarnation of "undefined behavior".
Your test for != 0 before calling deleteAllBooks() is redundant:
void deleteAllBooks ( Book *node )
{
if( node )
{
deleteAllBooks( node->left );
deleteAllBooks( node->right );
delete node;
}
}
does the same, but might be easier to understand.
And don't mix free/alloc with new/delete. If you've allocated an object with new, you have to return it with delete. Otherwise, you will get undefined behavior.
Related
I'm writing a linked list, and using my main function to test it. Here's my code:
#include <iostream>
using namespace std;
class LinkedList {
int value;
LinkedList* next;
public:
LinkedList(int valueIn, LinkedList* nextIn) {
value = valueIn;
next = nextIn;
}
LinkedList(int valueIn) {
value = valueIn;
}
int getValue() {
return value;
}
void addNode(LinkedList* node) {
next = node;
}
LinkedList& getNext() {
return *next;
}
};
int main() {
cout << "starting..." << std::endl;
LinkedList list1(1);
LinkedList list2(2, &list1);
cout << list1.getValue() << " --> " << list1.getNext().getValue() << std::endl;
return 0;
}
I expect the output to be 1 --> 2, but I get 1 -->. As far as I understand, getNext() should return a reference to another list (list2 in this case), but something seems to be going wrong. My debugging efforts show me that list2 does have the correct value 2 when it's initialized, but when it's referenced for the final output, it doesn't seem to have anything for value. I can't for the life of me figure out why this is. Could someone help me to understand?
You are insertin list1(which is actually a node) to the end of list2, not the other way around, yet you call getNext() on list1. You should change the code in main to the below:
int main() {
std::cout << "starting..." << std::endl;
LinkedList list1(1);
LinkedList list2(2, &list1);
std::cout << list2.getValue() << " --> " << list2.getNext().getValue() << std::endl;
return 0;
}
Please note that there are a couple of other things which would be better to change:
Create a list class and a Node class woud make things clearer
Initializing the pointer to be NULL(or nullptr from C++11) in the LinkedList(int valueIn) constructor
Return the pointer to the node in getNext() rather than copy the node
You are not getting a blank value. Actually your program is crashing when you are trying to call list1.getNext().getValue() as getNext() is returning reference to a NULL.
You are doing the opposite of what you want to do.
Your list2 is pointing to list1 and list1 is pointing to NULL.
You should change your code with this:
LinkedList list2(2);
LinkedList list1(1, &list2);
cout << list1.getValue() << " --> " << list1.getNext().getValue() << std::endl;
My program is a list of cities, it's good but when I call to popFront(), I don't know why but it doesn't work, then I call any function and the program is over.
City* popFront(Nodo*& header, Nodo*& trailer) {
City* libras;
if (inicio) {
strcpy(libras->Name,inicio->dato.Name );
libras->Num = header->dato.Num;
Nodo* aux = header;
header= header->next;
header->previous= NULL;
delete aux;
if (!header) trailer = NULL;
}
return libras;
}
void read(Nodo*& head) {
Nodo* aux = head;
int pos = 1;
while (pos <= node_count) {
cout << "pos" << pos << endl;
cout << "Name> " << aux->dato.Name << endl;
cout << "NUm> " << aux->dato.Num << endl;
aux = aux->next;
pos++;
}
if (node_count == 0)cout << "Empty list" << endl;
}
Well, I'm not sure this is the only problem, but this right here is wrong:
City* libras;
You need to allocate it before you use it, like this:
City* libras = new City;
Otherwise, something like strcpy(libras->Name,inicio->dato.Name ); will fall and crash hard. That's because it's UB (Undefined Behavior) to access a pointer to memory that is unallocated.
Of course, you will need to delete it when you're done with it, but you seem to know and understand that already based on your other code:
delete libras; // Or wherever the returned pointer gets stored
Background:
I donot know what caused me to experiment with this, but I am trying to test a containerised linked list which internally uses smartpointers.
Here is the repl link:
https://repl.it/#BasavarajNagar/GoodnaturedGlisteningSection-1
#include <memory>
using namespace std;
template<typename T>
class linkedlist {
private:
class node {
public:
T data;
shared_ptr<node> next;
node(T data) {
this->data = data;
}
};
// non const unique ptr
shared_ptr<node> head;
public:
void add(T data) {
cout<< "adding " << endl;// + data << endl;
if (head == nullptr) {
head = shared_ptr<node>(new node(data));
return;
}
shared_ptr<node> cursor;
cursor.swap(head);
// this works well
while (cursor != nullptr) {
cout << cursor->data << endl;
cursor = cursor->next;
}
cout << data << endl;
// this is the problematic assignment
cursor = shared_ptr<node>(new node(data));
}
void trace() {
shared_ptr<node> cursor;
cursor.swap(head);
cout << "trace" << endl;
while (cursor != nullptr) {
cout << cursor->data << endl;
cursor = cursor->next;
}
}
};
int main() {
std::cout << "Hello World!\n";
linkedlist<int> ll;
ll.add(22);
ll.add(45);
ll.add(63);
ll.trace();
}
The trace method always points to last element, the head is lost after swap during add method.
Note:
I know this is not production quality code, but to understand internals/quirks of smartpointers. So, pls avoid code quality comments.
You badly misunderstand shared pointers. https://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr
The trace info you need most is node::node and node::~node. Tracking when actual nodes get created and destroyed will help you. You also must understand scope.
A quick critique of your "add" function (fixes left to you, beyond the scope of the question and detrimental for me to post too much):
It creates a single item list correctly. However, if you try to add again, you move head to a temporary object, setting head to nullptr. You then loop cursor through the list, destructing any nodes that might have existed, until there are no more. The fact that you have just assigned nullptr to cursor is not a problem, because you immediately toss whatever value it might have had as you then create a new list with a single item, held by cursor instead of head. You then go out of scope, destructing cursor, and therefore also destructing that new item that you just added to cursor.
But the biggest problem is your trace function, which you are using to understand your list, but it's not doing anything remotely like what you want. This is the biggest problem, because you think you understand what is going on based on bad information. If trace lies to you, then you can't get anywhere using it to understand add.
Here is a trace function which will correctly print the current contents of your list, without destroying it:
void trace() {
cout << "trace: ";
shared_ptr<node> cursor = head; // SHARE, do not lose head, read the docs
while (cursor.get()) {
cout << cursor->data << ", ";
cursor = cursor->next;
}
cout << endl;
}
I would suggest calling the trace function twice in a row. If it's not destroying the list as it prints it, then the second call should have the same output as the first. To fix add, you need to simplify it. Just follow what you should do on a regular node pointer. Your big problem was using "swap" to place your actual data under the sole control of a temporary object, which will quickly DO ITS JOB, which is destroy all your data.
I have a problem with the following linked list code, but i'm not sure what it is. Could someone point me in the right direction? I'm using this code in some larger code where i update records, but it never reaches the "creating new record" section. It is as if the main code is updating the head pointer instead thus always resulting in a favourable comparison.
Thanks in advance. I've been racking my brains out trying to figure out what the problem is.
struct l_list *find_name(const char *name)
{
struct l_list *tmp=0;
if(records==0) { // First record
head=new l_list;
head->name=name;
head->next=0;
tail=head;
records++;
return head;
}
else {
tmp=head;
while(tmp!=0)
{
if(!std::strcmp(tmp->name,name))
{
cout << "Returning existing record with value: " << tmp->number << " name:" << tmp->name << endl;
return tmp;
}
tmp=tmp->next;
}
// No first and no existing records
cout << "Creating new record" << endl;
tail->next=new l_list;
tail=tail->next;
tail->name=name;
tail->next=0;
records++;
return tail;
}
I'm calling this from main with:
struct records *tmp=find_name("Max");
then :
tmp=find_name("Eva");
Once i get the struct i update it like so:
tmp->number=1;
Or even updating the name:
tmp->name="Peter";
So by passing a string to the function it will either create a new record and return it or give an existing record and return that. Problems might not be apparent in the output, but when you put it in a for(;;) loop in main it will
mess up.
The struct is as follows:
struct records {
const char *name;
struct records *next;
}
The relevant program code is:
struct record {
const char *name;
struct record *next;
};
struct record *head;
struct record *tail;
struct record *find_name(const char *name)
{
struct record *tmp=0;
if(record_count==0) { // First record
cout << "Creating first record" << endl;
head=new record;
head->name=name;
head->next=0;
tail=head;
record_count++;
return head;
} else {
tmp=head;
while(tmp!=0) {
if(!std::strcmp(tmp->name,name)) {
cout << "Returning existing record with value: " << "name: " << name << "tmp->name: " << tmp->name << endl;
return tmp;}
tmp=tmp->next;
}
// No first and no existing records
cout << "Creating new record" << endl;
tail->next=new record;
tail=tail->next;
tail->name=name;
tail->next=0;
record_count++;
return tail;
}
}
int main(int argc, const char *argv[])
{
struct record *tmp=0;
if(something is true) {
//Return or create a new user
tmp=find_name("Peter");
} else {
tmp=find_name("Unknown"); // Hold 1 unknown person in database
}
}
I know it's not compilable as-is but i had to extract it from a larger part.
Since you have not told us what the records structure is, there is no way for anyone to give a correct answer. You have made it even more impossible by not giving an example of code that will cause your function to behave incorrectly.
If the name element is a char * pointer then you could easily get this behaviour. For example:
The calling code puts a name into a buffer, and calls find_name.
find_name stores the address of the buffer into the name element of a records object. name therefore points to whatever the buffer happens to contain, now and in the future.
The calling code puts a new name into the same buffer. This automatically means that the name element now points to that new name, since it is pointing to the buffer.
The calling code calls find_name again.
find_name compares the contents of the buffer to the string pointed to by the name element of the first records object. Since the name element contains the address of the buffer passed by the caller (from step 2), this means that it is comparing the buffer to itself. So the result is always "equal".
But it may be that name is not a pointer at all, in which case this entire answer is irrelevant.
First of all do not use the following code formatting
if(record_count==0) { // First record
cout << "Creating first record" << endl;
//...
} else {
tmp=head;
//...
It is difficult to read such a code. It is just a bad style of programming.
The function itself can look the following way
struct l_list * find_name( const char *name )
{
struct l_list *tmp = head;
wjile ( tmp != nullptr && std::strcmp( tmp->name, name ) != 0 ) tmp = tmp->next;
if ( tmp == nullptr )
{
cout << "Creating new record" << endl;
tmp = new l_list;
tmp->name = name;
tmp->next = nullptr;
if ( tail == nullptr )
{
head = tail = tmp;
}
else
{
tail = tail->next = tmp;
}
records++;
}
return tmp;
}
Take into account that the nodes can contain pointers to strings either with the static storage duration as for example string literals or allocated in the heap.
working on a simple C++ pointer-based stack program. I am attempting to print a string which is part of the NameItem class which the PointerStack class uses as its item type (see code). Whenever I try to print the string in the main() function of my program, the console prints gibberish and beeps repeatedly. However, when I call the PrintPointerStack function, there are no errors and everything prints as expected.
I'd tried changing the classes, rearranging the code, and while I can pinpoint which line generates the error I can't figure out why. I'm completely lost here, never seen anything like this before, so I'm sorry if the answer is simple and found in a google search but I've been going for hours and just don't know what to search anymore.
Code is below:
#include <iostream>
#include <string>
#include <stack>
#include <cstddef>
#include <new>
using namespace std;
#include "NameItem.cpp"
#include "Stack.cpp"
#include "PointerStack.cpp"
void PrintPointerStack(PointerStack printer){
NameItem temp;
while(!printer.IsEmpty()){
temp = printer.Top();
printer.Pop();
temp.Print();
}
cout << endl;
}
int main(){
string initNames[] = {"Michael","Charlie","Susan","Alexa",
"Jason","Candice","Beatrice","Lois",
"Peter","Matthew"};
int initNamesLen = 10;
PointerStack PStacker, tempPStacker;
NameItem filler;
for(int i = 0; i < initNamesLen; i++){
filler.Init(initNames[i]);
PStacker.Push(filler);
}
cout << endl << "---------- Pointer-based Stack ----------" << endl << endl;
PrintPointerStack(PStacker);
cout << "Top: ";
(PStacker.Top()).Print(); //This is where the program errors. I've tried creating a
//temp variable like in the function above, and I've
//tried accessing the string directly and printing it
//from main() using cout, which produce the same results.
//So the error is caused specifically by the cout <<
//string statement, when I try to use that statement
//within the bounds of the main function.
cout << endl;
PrintPointerStack(PStacker);
cout << endl << "Popped: ";
(PStacker.Top()).Print();
PStacker.Pop();
(PStacker.Top()).Print();
PStacker.Pop();
cout << endl;
PrintPointerStack(PStacker);
cout << endl << "Pushed: Sammy Valerie" << endl;
filler.Init("Sammy");
PStacker.Push(filler);
filler.Init("Valerie");
PStacker.Push(filler);
PrintPointerStack(PStacker);
try{
PStacker.Push(filler);
}
catch(FullStack){
cout << endl << "Stack is full, name not pushed" << endl;
}
cout << endl << "Popped: ";
while(!PStacker.IsEmpty()){
filler = PStacker.Top();
PStacker.Pop();
filler.Print();
}
try{
PStacker.Pop();
}
catch(EmptyStack){
cout << endl << "Stack is empty, name not popped" << endl;
}
return 0;
}
The PointerStack class
#include "PointerStack.h"
PointerStack::PointerStack(){
top = NULL;
}
/*PointerStack::~PointerStack(){
Node* temp;
while(top != NULL){
temp = top;
top = top->next;
delete temp;
}
}*/
void PointerStack::Push(NameItem item){
if(IsFull())
throw FullStack();
else{
Node* location;
location = new Node;
location->data = item;
location->next = top;
top = location;
}
}
void PointerStack::Pop(){
if(IsEmpty())
throw EmptyStack();
else{
Node* temp;
temp = top;
top = top->next;
delete temp;
}
}
NameItem PointerStack::Top(){
if(IsEmpty())
throw EmptyStack();
else{
return top->data;
}
}
bool PointerStack::IsEmpty() const{
return (top == NULL);
}
bool PointerStack::IsFull() const{
Node* location;
try{
location = new Node;
delete location;
return false;
}
catch(std::bad_alloc& exception){
return true;
}
}
And the NameItem class
#include <fstream>
#include "NameItem.h"
NameItem::NameItem()
{
name = " ";
}
RelationType NameItem::ComparedTo(NameItem otherItem) const
{
if (name < otherItem.name)
return LESS;
else if (name > otherItem.name)
return GREATER;
else
return EQUAL;
}
void NameItem::Init(string value)
{
name = value;
}
void NameItem::Print() const
{
cout << name << " ";
}
Final note, the main program has more code for testing the Stack class included in the program. I removed the code since it is not related to the error, and the program still crashes, but it crashes immediately with a windows error box rather than with console gibberish/beeps. Not sure if that is relevant or not...
The problem is twofold.
First, you are emptying the PStacker object in PrintPointerStack(), then trying to access the top element of that empty stack. This should throw an EmptyStack. The fact that this is not happening, indicates another problem as well (see below).
Second, the fact that giberish is printed (sometimes) indicates that you are trying to access data through invalid objects/pointers. Indeed, because you are passing the parameter of PrintPointerStack() via pass-by-value, the default copy-constructor is invoked that blindly copies the value of the top pointer. Then you proceed to delete objects, but the top pointer in the original PStacker is not changed, thus now is invalid. Hence your problem.
To fix, you either need to pass the parameter to PrintPointerStack() by pointer/reference or provide a better suiting copy-constructor that does a deep copy (instead of the shallow copy provided by the default copy-constructor).