C++: Tree node not updating - c++

I am trying to update a node with a new value, but when I print out the node in another function, the old value is being displayed. I have also tried setting 'question' to the return value of updateTree(), in which it would return the new updated node, but that yields the same result.
void f(Node *n){//n is a pointer that has a string value with a left and right pointer. lets say that "n" right now is "duck"
//do stuff....
updateTree(n);
cout << n->value;//prints out "duck" rather than the updated value..
}
void updateTree(Node *question){
string animal, q;
cout << "Darn, I lost. What was is? ";
getline(cin, animal);
cout << "Enter a question that is true for a(n) " << animal << " and false for a(n) " << question->value << ": ";
getline(cin, q);
Node right(question->value, nullptr, nullptr);//the old animal ie "duck"
Node left(animal, nullptr, nullptr);//the new animal
question = new Node(q, &left, &right);//updated "n" ie "duck" to something else
}

Your code
void updateTree(Node *question) {
// ^^^^^^ That's a copy of the pointer variable passed.
// Assignments will never affect the original pointer value
// ...
question = new Node(q, &left, &right);
}
sends the newly created Node to void, it's lost as soon that function leaves scope. You're operating on a copy of that pointer variable.
What you actually need is a reference that allows changing the original pointer:
void updateTree(Node*& question) {
// ^

Related

Trying to write my own linked list impementation in c++, code segfaults after hitting 3 elements in the list

I've been trying to write my own implementation of linked list, but the code segfaults when I try to access an the third element or anything after it. Adding elements doesn't segfault, but accessing does. I can't find the pointer error in my get() function.
Each node in the list stores data (of Template t) and a pointer leading to the next node. I have two functions for everything- one for the first element, and one for any subsequent elements. The get() function for the subsequent elements always segfaults. I have some debug messages in the function that spit out results I can't explain. For example, if I run a get() request for the second element, an then the third, the code doesn't segfault, but it does return clearly incorrect results. Debug messages I placed indicate the segfault occurs when the second element calls the function to check the third element, if it occurs at all. Try the code with and without the line cout << newList.get(2) << endl; and you'll get very different results.
One possible cause is the pointer storage- I have the get() function output the pointer of each element (except the first) as it cycles through, and compare them to the pointers outputted by the add() function, and and pointers for element 0 and 1 match, but 2 and beyond do not match, and I can't seem to figure out why that would be.
#include <iostream>
using namespace std;
template <class T> class myLinkedList{
T data;
myLinkedList<T> *next = NULL;
public:
myLinkedList(T input){
data = input;
}
void add(T input){
if(next == NULL){
myLinkedList<T> newItem(input);
next = &newItem;
cout << "adding to list, data is " << input << ", pointer is " << next << endl;
}else{
myLinkedList<T> nextEntry = *next;
nextEntry.add(input);
}
}
T getData(){
return data;
}
//the start of the get function, only used by the first entry in the list
T get(int entry){
int currentPosition = 0;
if(entry == currentPosition){
return getData();
}else{
//defrefrence the pointer anc check the next entry
myLinkedList<T> nextEntry = *next;
return nextEntry.get(entry, ++currentPosition);
}
}
private:
//this vesion is the hidden, private vesion only used by nodes other than the first one
//used to keep track of position in the list
T get(int entry, int currentPosition){
//cout << currentPosition << endl;
if(entry == currentPosition){
return data;
}else{
//derefrence the pointer and check the next entry
cout << next << endl;
myLinkedList<T> nextEntry = *next;
currentPosition++;
T output = nextEntry.get(entry, currentPosition);
return output;
}
}
};
int main(){
myLinkedList<int> newList(3);
newList.add(4);
newList.add(5);
newList.add(7);
newList.add(9);
cout << newList.get(2) << endl;
cout << newList.get(3) << endl;
return 0;
}
Results are clearly erroneous- program should spit oout two macthing sets of pointers, as well as the numbers 5 and 7 ( the list elements)
One of your main problems is here:
if(next == NULL){
myLinkedList<T> newItem(input); // <<<<<<<<<<<<<
next = &newItem;
cout << "adding to list, data is " << input << ", pointer is " << next << endl;
}
you allocate an item on stack inside the if scope. Then you make next to point to this item. But... lifetime of the item is bounded by this scope. As son as you exit the scope, this item does not exist any longer. You need to allocate it dynamically by 'new' or other methods.
I had a breakthrough! Following Serge's solution was helpful, but one more change was needed- rather than create a function reference in the else block of my add function,
eg
myLinkedList<T> nextEntry = *next;
nextEntry.add(input)
i needed to use the pointer directly, as in
next->add(input)
I didn't know my pointer/object syntax

linked list not working properly, head updated instead

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.

Using a map that has a abstract base class pointer and calling a derived class function

I've searched on the web and can't find any solutions to my problem I hope you can help.
So I have constructed an abstract base class and have two derived classes that represents different experiments. (one is actually a derived derived class of my base class) And I made a map as such in a separate header file to store different types of experiments.
//Map class template to store name of experiment and the experiment within a project
typedef map <string, baseData <double>*> ExpContainer;
void search(string searchName, ExpContainer exps) {
ExpContainer::iterator Iter;
Iter = exps.find(searchName); //finds the entry corresponding to searchName and returns the iterator
if (Iter != exps.end()) { //need this as if entry is not found, the return will be end iter.
cout << "Found the experiment " << Iter->first << "." << endl;
Iter->second->print();
}
else {
cout << "Sorry, experiment " << searchName << " is not found" << endl;
}
}
The print() function is different for each experiment type and I know there's a problem called slicing so I've made sure that print() is virtual in the base class. Here's my base class:
namespace mynmsp {
//base class of data can be measurements or errors
template < class T> class baseData {
public:
virtual void print() =0;
virtual ~baseData() {
cout << "Destructor called for the base class." << endl;
}
};
}
Then in my main.cpp I've constructed different types of experiment and I want to print them. Each experiment class has different implementation of the print function that overrides the print function from the base class, like:
void print(){ //do something };
And in my main.cpp I have the map defined as:
ExpContainer project;
And after I have constructed each experiment, I've asked the user for the name of the experiment (expName) and inserted into project as such:
project[expName] = &expC;
I think the insertion is fine as I tested the size of project and it was correct.
However, a runtime error occured when my search function was called like this:
search(name, project);
I don't know if there's a problem with slicing or with my pointers?
I tried to make print() a virtual function in each derived class but that doesn't seem to work either.
Apologies for the long question, please help!
Edit: I've constructed my experiments inside a do while loop while project is declared outside. The whole code is very long but its basics is something like this:
string repeatstr; //user input whether to repeat do while loop or not
bool repeat = true; //condition for staying inside do while loop
ExpContainer project; //declared project to store experiments
do {
string expName;
string ans1; //character to store user input
cout << "What is the name of your experiment? " << endl;
cin >> expName;
cout << "Is this a experiment C ? (y/n)" << endl;
cin >> ans1;
if(ans1 =="y"){
//call the constructor for expC
project[expName] = &expC;
}else {
//call the constructor for expB
project[expName] = &expB;
}
cout << "Do you want to enter another experiment? (y/n)" << endl;
cin >> repeatstr;
if (repeatstr == "n") { repeat = false; }
}while (repeat); //loop over this do-while loop while repeat is true
cout << "There are " << project.size() << " in this database." << endl;
//to retrieve info from a certain experiment
string input, name;
cout << "Would you like to retrieve any experiments (y/n)? " << endl;
input = EitherInput("y", "n");
if (input == "y") {
cout << "Please enter the name of the experiment you want to retrieve: " << endl;
cin >> name;
search(name, project); //code breaks down here!
}
You are saving a pointer to the object that was already destroyed. You can check the addresses that you have in the map, most probably they are the same. You should store your experiment object in dynamic memory
if(ans1 =="y")
{
project[expName] = new expC();
} // Scope ends here and all variable created in it will be destroyed.
else
{
project[expName] = new expB();
} // Scope ends here and all variable created in it will be destroyed.
And after you are done with them you need to call delete on each pointer to avoid memory leak. Also you need to check if the items in the map are already existing, otherwise you will loose pointers to allocated memory which is automatically a memory leak.
I would recommend you to use std::share_ptr< baseData<double> > instead of bare baseData<double>*. Here you can read more about it. And also consider using typedef in order to have more clear syntax.
P.S.
The function
void search(string searchName, ExpContainer exps)
will copy whole map to its body. Use constant reference instead
void search(string searchName, const ExpContainer& exps)
But then you'll also need to declare function print as const:
virtual void print() const = 0;
and override it with const modifier:
virtual void print() const override;
And use constant iterator ExpContainer::const_iterator Iter

Trouble calling an object's method using a pointer to that object

So I normally wouldn't bother posting about such a simple thing but I can't for the life of me figure out what I'm doing wrong and it's probably something very simple that i'm over looking.
Getting straight to the point, I'm making an object pointer and then using that pointer to call a method of that particular object.
But for some reason whenever I cout the function as follows:
Entry FirstEntry = Entry(J1,H1);
cout << FirstEntry.getItem() << endl;
cout << FirstEntry.getKey() << endl;
Entry *siz = new Entry();
cout << siz->getItem() << endl;
It gives me a blank line being output. Whereas it should be giving me my item value.
The Object itself looks like such:
Entry::Entry()
{
}
Entry::Entry(KeyType & Key, ItemType & newItem)
{
setKey(Key);
setItem(newItem);
}
Entry::~Entry()
{
}
ItemType Entry::getItem() const
{
return item;
}
KeyType Entry::getKey() const
{
return searchKey;
}
void Entry::setItem(const ItemType & newItem)
{
item = newItem;
}
void Entry::setKey(const KeyType & Key)
{
searchKey = Key;
}
I've been staring at this code for awhile and I can't quite figure out what's causing it to output just a blank line.
Thank you very much for your patience,
Okay, thanks to the two posts it's super obvious what I'm doing wrong here, when I created my pointer to my object I was pointing towards the constructor which didn't set any values and thus when I was returning values through my pointer technique it was giving me the accurate values. They were just empty values, hence it was putting out an empty line.
The Fix:
Entry *siz = new Entry(J1,H1); //This line didn't hold parameters to call right constructor
cout << siz->getItem() << endl;

c++ Linked List losing data between functions

I am having a problem with pointers and scope. I am trying to maintain an array of linked lists of pointers to objects. When I try to push_front() in one function, it works. However, if I try to iterate through the list in another part of my program, the list no longer contains any data, and my pointers are bad.
This is part of my parseCommands function. the problem is when printList is called:
Administrator *adminPtr = new Administrator(); // create new Administrator pointer
//local variables...
string adminName; //administrator's name
int adminMNum; //administrator's M Number
string adminEmail; //administrator's email address
string adminTitle; // administrator's title
// read in & store data for new administrator
inData >> adminName; //read in data
adminPtr->setName(adminName); //set admin name
inData >> adminMNum;
adminPtr->setMNum(adminMNum); // set admin M Number
inData >> adminEmail;
adminPtr->setEmail(adminEmail); // set admin email address
inData >> adminTitle;
adminPtr->setTitle(adminTitle); //set admin title
// finished storing new administrator info
// add Administrator to list
cout << "Adding Administrator: " << endl;
cout << "in records office adminPtr/newPerson: " << adminPtr << endl;
universityList.addPerson(adminPtr); // call addPerson--hashTable
//universityList.printPerson(adminPtr); // print admin info using polymorphic method
//cout << "The load factor (alpha) is: " << universityList.getLength()/universityList.getMaxTableSize() << endl; // print alpha
universityList.printList(adminPtr->getMNum()); // print all items at table[loc]--breaks here
cout << endl;
The addPerson function where printList works fine:
template <typename T>
void HashTable<T>::addPerson(T newPerson) { //newPerson is a pointer to a person object
int loc; // array location provided by hashFunction
cout << "in hashtable newPerson: " << newPerson << endl;
loc = hashFunction(newPerson->getMNum()); // get loc
table[loc].push_front(&newPerson); // add to list at table[loc] passing address of pointer to person
printList(newPerson->getMNum()); // print all items at table[loc]--works here
size++; // increment size
} //end function
The printList function that works when called in addPerson, but not in parseCommands:
template <typename T>
void HashTable<T>::printList(searchKeyType key) { //print list of items held in array location
int loc = hashFunction(key); // get array location
if (table[loc].empty()) { // if list is empty
cout << "Can not print person M" << key << " NOT found" << endl << endl;
} //end if empty
else{
list<T*>::iterator iter; // stl iterator
iter = table[loc].begin();
cout << "in printList table[loc]begin " << *iter << endl; //print address of table[loc]begin.()--where iter points
cout << "in printList item in table[loc]begin " << **iter << endl; // print address of the pointer that iter points to
while(iter != table[loc].end()) { // for each item in the list
(**iter)->print(); // print person info using polymorphic method
++iter;
} //end for
} // end else
} // end printList
The print function:
void Administrator::print()const {
// print Administrator info
cout << " " << "Full Name: " << getName() << endl;
cout << " " << "M Number : "<< getMNum() << endl;
cout << " " << "Email Addr: " << getEmail() << endl;
cout << " " << "Title: " << getTitle() << endl;
}; // end print function
The hashTable class:
template<typename T>
class HashTable{
public:
HashTable(); // constructor
bool isEmpty()const; //determines if the hash table is empty
int getLength() const; // returns (size) number of Persons in table (accessor)
int getMaxTableSize() const; // returns tableSize (size of array)
void addPerson(T person); // adds new Person
void removePerson(searchKeyType key); // deletes Person from the HashTable
void printPerson(T person); // prints Person info
T getNodeItem(int mNumber); //returns person object (accessor)
void printList(searchKeyType key); //print list of items held in array location
private:
int size; // number of Persons in table
static const int tableSize = 1; // number of buckets/array size -- planning on using 70001--assuming 35,000 entries at once; largest prime > 2*35000
list <T*> table[tableSize]; // array of STL lists for chains
int hashFunction(searchKeyType searchKey); // hash function to return location (array index) of item
}; //end HashTable class
I pass adminPtr to addPerson, and it seems to add it to the list. Why am I losing the data when I return to the parseCommands function? Is it a stack vs. heap issue? Do I need "new" somewhere? There are a few extra lines in there where I was printing out the address of the pointers trying to figure out what's going on.
This was a programming problem for a class that I was unable to resolve. We had to simulate a hash table using an array of STL linked lists. We were not allowed to use vectors, maps, etc. The program involves an abstract base class (Person) with derived classes (Administrator, etc.) and a templated hash table class. There is one more class (RecordsOffice) that holds the hash table.
class RecordsOffice {
public:
RecordsOffice(); // default constructor
void parseCommands(string fileName); // function to parse commands from a file to maintain the StudentList
private:
HashTable <Person*> universityList; // creates empty hashtable
};
The problem is in these two places.
universityList.addPerson(adminPtr);
//...
You are passing a copy of adminPtr.
template <typename T>
void HashTable<T>::addPerson(T newPerson) { //newPerson is a pointer to a person object
// ...
table[loc].push_front(&newPerson); // add to list at table[loc] passing address of pointer to person
// ....
}
newPerson is a local variable to addPerson. When it returns it is no more valid. But you are adding it´s address in to the table.
the issue is that
list <T*> table[tableSize];
is storing pointers to pointers of Person.
I don't think passing by reference would solve the problem too. Because then you will be dependent on the automatically created pointer here.
Administrator *adminPtr = new Administrator();
What adminPtr pointer points to will stay but not adminPtr itself. So you can not depend on its address (unless you are sstill in the same function that created it). One possible way to solve it would be to allocate adminPtr itself dynamically.
Administrator **adminPtr = new Administrator*;
adminPtr = new Administrator();
But maybe you should revise the requirements.
Your table is declared like this:
list <T*> table[tableSize];
That means any pointers it contains need to be dynamically allocated, or need to remain in scope for the entire lifetime of the container. This is not the case. In your function addPerson you add the address of a local variable:
table[loc].push_front(&newPerson);
You should do one of the following:
Change the table to an array of list<T> objects.
Copy the data dynamically. eg table[loc].push_front(new T(newPerson))
Because this is a list, I would go for option 1 because the list will copy locally anyway, and you won't have to clean up the pointers later. A third option would be to use list<unique_ptr<T> > or similar.