Why is the pointer's value changing in while loop? - c++

I have the following code:
#include <iostream>
#include <cstring>
using namespace std;
class lexicon{
private:
class node{
public:
string s = "";
int freq;
node *left=nullptr;
node *right=nullptr;
friend class lexicon;
};
node *root;
public:
void display(node *pd)const{
if(pd==nullptr)return;
display(pd->left);
cout << root->s << " " << root->freq << endl;
display(pd->right);
}
lexicon(){
root=nullptr;
}
~lexicon(){
delete root;
}
void insert(const string &s1){
if(root==nullptr){
root= new node;
root->s=s1;
root->freq=1;
root->left=root->right=nullptr;
}else{
node *point=root;
string s6 = point->s;
if(point->s!=s1)cout << "1";
node *pppp=point;
while(s1!=(point->s) && point!=nullptr){ //this is where the problem occurs
if(s1>(point->s))point=point->right;
else if(s1<(point->s))point=point->left;
}
if(point==nullptr){
point = new node;
point->s=s1;
point->freq = 1;
point->left=point->right=nullptr;
}else{
++(point->freq);
}
}
}
int lookup(const string &s)const{
node *point=root;
if(point==nullptr)return 0;
while(point->s!=s && point!=nullptr){
if(s>point->s)point=point->right;
else if(s<point->s)point=point->left;
}
if(point==nullptr)return 0;
else return point->freq;
}
int depth(const string &s)const{
int count = 1;
node *point=root;
if(point==nullptr)return 0;
while(point->s!=s && point!=nullptr){
if(s>point->s)point=point->right;
else if(s<point->s)point=point->left;
++count;
}
if(point==nullptr)return 0;
else return count;
}
void replace(const string &s1, const string &s2){
int side;
node *point1=nullptr;
node *point=root;
if(point==nullptr)return;
while(point->s!=s1 && point!=nullptr){
point1=point;
if(s1>point->s){point=point->right; side=1;}
else if(s1<point->s){side=-1; point=point->left;}
}
if(point==nullptr)return;
int k=point->freq;
if(point->right==nullptr && point->left!=nullptr){
if(side==1)point1->right=point->left;
if(side==-1)point1->left=point->left;
point->left=nullptr;
delete point;
}else if(point->left==nullptr && point->right!=nullptr){
if(side==1)point1->right=point->right;
if(side==-1)point1->left=point->right;
point->right=nullptr;
delete point;
}else if(point->left==nullptr && point->right==nullptr){
if(side==1)point1->right=nullptr;
if(side==-1)point1->left=nullptr;
delete point;
}else{
node *small = point->left;
if(small->right==nullptr){
small->right=point->right;
if(side==1)point1->right=small;
if(side==-1)point1->left=small;
point->right=point->left=nullptr;
delete point;
}else{
node *smallb, *small=point->left;
while(point->right!=nullptr){
smallb=small;
small=small->right;
}
smallb->right=small->left;
if(side==1)point1->right=small;
if(side==-1)point1->left=small;
small->right=point->right;
small->left=point->left;
point->left=point->right=nullptr;
delete point;
}
}
node *start=root, *startb;
int ns=0;
while(start->s!=s2 && start!=nullptr){
startb=start;
if(s2>start->s){ns=1; start=start->right;}
if(s2<start->s){start=start->left; ns=-1;}
}
if(start==nullptr){
if(ns==1){
startb->right=new node;
(startb->right)->s=s2;
(startb->right)->freq=k;
}if(ns==-1){
startb->left=new node;
(startb->left)->s=s2;
(startb->left)->freq=k;
}
}else{
start->freq+=k;
}
}
friend ostream & operator<<(ostream &out, const lexicon &l){
l.display(l.root);
return out;
}
};
int main(){
cout <<"1";
lexicon l;
l.insert("the");
l.insert("boy");
l.insert("and");
l.insert("the");
l.insert("wolf");
cout << "the word 'the' is found " << l.lookup("the") << " tine(s)" << endl;
cout << "the word 'and' is found at depth " << l.depth("and") << endl;
cout << l;
l.replace("boy", "wolf");
cout << "Aftr replacement:" << endl;
cout << l;
cout << "Now the word 'and' is found at depth: "<<l.depth("and")<<endl;
return 0;
}
When i run it through a debugger it stops at the line i have the comment at, with a segmentation fault error. As you can see i set the point to be equal to root and then i set pppp to be equal to point. The debugger shows that root has a value of 0x615c50, but the point has a value of 0x0. And the weirdest thing is that pppp has the correct value 0x615c50. I don't know why point's value is set to 0x0 when i call the while loop. The debugger I used is onlinegdb. The pictures i attached show the value of the variables at the right side, just after is shows the segmentation fault at this line. Thanks for any help in advance.

Why is the pointer's value changing in while loop?
while(s1!=(point->s) && point!=nullptr){ //this is where the problem occurs
if(s1>(point->s))point=point->right;
else if(s1<(point->s))point=point->left;
}
You are changing the value of point in both branches of the if block. Of course point is changing in the loop.
The problem in your code is that you are dereferencing the pointer in point->s even when point has been set to nullptr.
You need to change the conditional of the while statement to:
while ( point != nullptr && s1 != (point->s) { ... }

Your condition is the wrong way around:
while(s1!=(point->s) && point!=nullptr)
You should first check if point is valid before you dereference it. Ie change that to
while(point!=nullptr && s1!=(point->s))
There might be more problems in your code though..

Related

How can I traverse a Huffman Tree (via code) and print out the encodings for each letter?

I'd like to start with what I know about heaps and Huffman code.
For this project, we use a minimum heap. The top part of the upside-down tree (or root) holds the minimum element. Whenever something is added to the array, everything gets moved, so the root is always the minimum value element. Whenever an element is deleted, everything gets reconfigured with the top element holding the minimum once again. In class, we went over a (template) class called MaxHeap, which I converted into MinHeap without the template stuff.
My professor went over Huffman encoding, but I understood it best using this visual tool:
https://people.ok.ubc.ca/ylucet/DS/Huffman.html
The idea is to use a minimum heap as follows:
1. Delete two nodes
2. Create a new node with the deleted nodes as children. The frequency of this node is the summation of the two children frequencies.
3. Add this new node to the minimum heap
This process repeats until there is one node left in the heap (the root). Next, we find the encodings for each letter. To do this, travel down the tree with left movement being 0 and right movement being 1. Traveling right twice then left once would give 110 for the letter 'c' in my tree (image link can be found towards the bottom of my post).
Everything was going mostly fine until I needed to traverse from the root. I had no idea how to do this via code, so I tried googling the answers and found these two websites:
https://www.geeksforgeeks.org/huffman-coding-greedy-algo-3/
https://www.programiz.com/dsa/huffman-coding
I copied their function printCodes() into my code, but I didn't get see it work.
When I try manually going down the tree, I get two things. For example, I tried traveling left down the root and using cout to see the values. I expected to see 40, !, e, d; but when I tried I was getting gibberish number and characters (greek letters like theta, sigma, etc). It gets really weird because on line 207, yourRoot->left->freq gives me 40, but the same thing on the line 208 of code gives me a large number. When I traveled right, I got: Exception thrown: read access violation. yourRoot->right->right->letter was 0xCCCCCCCC.
To reiterate cout << yourRoot->left->freq << endl; will give me 40 the first time I call it, but the second time I get a random number. I expected the same output twice in a row. Am I supposed to keep a pointer or pointer-to-pointer to the address of yourRoot or something?
Another problem is in createHuffmanTree(), if I put return root; outside the while loop I get this error and the code doesn't run at all:
potentially uninitialized local pointer variable 'root' used
Both of these things were odd problems and I assume it has to do with the way I'm using & and * symbols. I tried using something like this:
MinHeap yourHeap = MinHeap(6);
node *item = newNode(30, 'f');
yourHeap.Insert(*item);
item = newNode(20, 'e');
yourHeap.Insert(*item);
item = newNode(20, 'd');
yourHeap.Insert(*item);
item = newNode(15, 'c');
yourHeap.Insert(*item);
item = newNode(10, 'b');
yourHeap.Insert(*item);
item = newNode(5, 'a');
yourHeap.Insert(*item);
delete item;
This works the same as the yourList[] code I have in main(), but I figured "keep it simple stupid" and avoid using pointers since I clearly have some issues with them.
I uploaded an output without any error causing code and a drawing of what I expect my tree to look like with the values I want to use (https://imgur.com/a/Vpx7Eif). If the link doesn't work, please let me know so I can fix it.
The code I have thus far is:
#include <iostream>
using namespace std;
#define MAX_TREE_HEIGHT 20
//exception is thrown if wrong input
class NoMem
{
public:
NoMem() { cout << "Heap is full\n"; }
};
class OutOfBounds
{
public:
OutOfBounds() { cout << "Heap is empty\n"; }
};
struct node
{
int freq;
char letter;
struct node *left, *right;
};
// initialize node with frequency and letter
node* newNode(int freq, char letter)
{
node *temp = new node;
temp->freq = freq;
temp->letter = letter;
temp->left = nullptr;
temp->right = nullptr;
return temp;
}
// initialize node using two nodes as children
node* newNode(node& a, node& b)
{
node *temp = new node;
temp->freq = a.freq + b.freq;
temp->letter = '!';
temp->left = &a;
temp->right = &b;
return temp;
}
class MinHeap {
public:
MinHeap(int MSize)
{
MaxSize = MSize;
heap = new node[MaxSize + 1];
Size = 0;
}
~MinHeap() { delete[] heap; }
MinHeap& Insert(node& x);
MinHeap& Delete(node& x);
void Display();
int Size;
private:
int MaxSize;
node *heap;
};
MinHeap& MinHeap::Insert(node& x)
{
if (Size == MaxSize) throw NoMem();
else
{
printf("Inserting '%c' with frequency of %d. ", x.letter, x.freq);
int i = ++Size;
while (i != 1 && x.freq < heap[i / 2].freq)
{
heap[i] = heap[i / 2];
i /= 2;
}
heap[i] = x;
Display();
return *this;
}
}
MinHeap& MinHeap::Delete(node& x)
{
if (Size == 0) throw OutOfBounds();
x.freq = heap[1].freq; // root has the smallest key
x.letter = heap[1].letter;
printf("Deleting '%c' with frequency of %d. ", x.letter, x.freq);
node y = heap[Size--]; // last element
int vacant = 1;
int child = 2; //make child = left child
while (child <= Size)
{
if (child < Size && heap[child].freq > heap[child + 1].freq) ++child;
// right child < left child
if (y.freq <= heap[child].freq) break;
heap[vacant] = heap[child]; // move smaller child
vacant = child; // new vacant
child = child * 2; // new child of vacant
}
heap[vacant] = y;
Display();
return *this;
}
void MinHeap::Display()
{
printf("Your heap contains: ");
for (int i = 1; i <= Size; i++)
printf("'%c' = %d, ", heap[i].letter, heap[i].freq);
printf("\n");
}
node* createHuffmanTree(MinHeap& yourHeap)
{
cout << "--- Creating Huffman Tree ---\n";
node left, right, *root;
while (yourHeap.Size > 1)
{
yourHeap.Delete(left);
yourHeap.Delete(right);
root = newNode(left, right);
cout << "-> New Node: freq = " << root->freq << ", letter = " << root->letter << ", left: " << root->left->letter << ", right: " << root->right->letter << endl;
yourHeap.Insert(*root);
if (yourHeap.Size < 2)
{
return root;
}
}
//return root; // potentially uninitialized local pointer variable 'root' used
}
void outputHuffmanCode(node* root, int arr[], int top)
{
// left movement is 0
if (root->left)
{
arr[top] = 0;
outputHuffmanCode(root->left, arr, top + 1);
}
// right movement is 1
if (root->right)
{
arr[top] = 1;
outputHuffmanCode(root->right, arr, top + 1);
}
// if reached leaf node, must print character as well
if (!(root->left) && !(root->right))
{
cout << "'" << root->letter << "' = ";
for (int i = 0; i < top; ++i)
cout << arr[i];
cout << endl;
}
}
int main()
{
node yourList[6];
yourList[0].freq = 5;
yourList[0].letter = 'a';
yourList[1].freq = 10;
yourList[1].letter = 'b';
yourList[2].freq = 15;
yourList[2].letter = 'c';
yourList[3].freq = 20;
yourList[3].letter = 'd';
yourList[4].freq = 20;
yourList[4].letter = 'e';
yourList[5].freq = 30;
yourList[5].letter = 'f';
cout << "Here is your list: ";
for (int i = 0; i < 6; i++)
{
cout << "'" << yourList[i].letter << "' = " << yourList[i].freq;
if (i < 5) cout << ", ";
} cout << endl;
MinHeap yourHeap(6);
yourHeap.Insert(yourList[5]);
yourHeap.Insert(yourList[4]);
yourHeap.Insert(yourList[3]);
yourHeap.Insert(yourList[2]);
yourHeap.Insert(yourList[1]);
yourHeap.Insert(yourList[0]);
/*
MinHeap yourHeap = MinHeap(6);
node *item = newNode(30, 'f');
yourHeap.Insert(*item);
item = newNode(20, 'e');
yourHeap.Insert(*item);
item = newNode(20, 'd');
yourHeap.Insert(*item);
item = newNode(15, 'c');
yourHeap.Insert(*item);
item = newNode(10, 'b');
yourHeap.Insert(*item);
item = newNode(5, 'a');
yourHeap.Insert(*item);
delete item;
*/
node *yourRoot = newNode(0, NULL);
yourRoot = createHuffmanTree(yourHeap);
// same cout twice in a row, different results
//cout << yourRoot->left->freq << endl;
//cout << yourRoot->left->freq << endl;
cout << "L0 Root: freq = " << yourRoot->freq << ", letter = " << yourRoot->letter << ", left freq: " << yourRoot->left->freq << ", right freq: " << yourRoot->right->freq << endl;
cout << "L11 Left: freq = " << yourRoot->left->freq << ", letter = " << yourRoot->left->letter << ", left: " << yourRoot->left->left->letter << ", right: " << yourRoot->left->right->letter << endl;
//cout << "R11 Left: freq = " << yourRoot->right->freq << ", letter = " << yourRoot->right->letter << ", left: \n";
//<< yourRoot->right->left->letter << ", right: " << yourRoot->right->right->letter << endl;
//int arr[MAX_TREE_HEIGHT], top = 0;
//outputHuffmanCode(yourRoot, arr, top);
system("pause");
return 0;
}
I'd like to thank whoever reads and replies to this post in advance. I think I've given as much information as I could. If I did anything that's against community rules, please let me know so I can fix my mistake(s).
In your createHuffmanTree Function, you create the node's left and right...
with root = newNode(left, right); you let the left/right member of your struct point to the address of the (temporary) node you've created in createHuffmanTree (that means in
node* newNode(node& a, node& b)
the address of a and b is always the same..
and the node goes out of scope after leaving the createHuffmanTree function - i think this causes your problem. You know what I mean?

C++ binary search tree creates segmentation fault

I'm trying to make a program that identifies AVR assembly instructions by opcode, since those are just a list of 1's and 0's I thought it would be a good project to make a binary search tree for.
Sadly I keep getting segmentation faults when trying to search through the tree. As I understand it a seg fault is usually the result of trying to do stuff with a pointer that doesn't point to anything, but since I have a Boolean that I check first that should never happen.
I'm pretty sure it has something to do with the way I use pointers, as I'm not very experienced with those. But I can't seem to figure out what's going wrong.
Below is the code involved (SearchTree is only a global variable in this minimal example, not in the real program.):
The code:
#include <iostream>
void ADD(short &code) {std::cout << code << "\n";}
void LDI(short &code) {std::cout << code << "\n";}
void SBRC(short &code){std::cout << code << "\n";}
struct node
{
void(* instruct)(short &code);
bool hasInst = false;
struct node *zero;
bool hasZero = false;
struct node *one;
bool hasOne = false;
};
node SearchTree;
auto parseOpcode(short code, node *currentRoot)
{
std::cout << "Looking for a: " << ((code >> 15) & 0b01 == 1) << std::endl;
std::cout << "Current node 1: " << (*currentRoot).hasOne << std::endl;
std::cout << "Current node 0: " << (*currentRoot).hasZero << std::endl;
// Return instruction if we've found it.
if ((*currentRoot).hasInst) return (*currentRoot).instruct;
// Case current bit == 1.
else if ((code >> 15) & 0b01 == 1)
{
if ((*currentRoot).hasOne) return parseOpcode((code << 1), (*currentRoot).one);
else throw "this instruction does not exist";
}
// Case current bit == 0.
else {
if ((*currentRoot).hasZero) return parseOpcode((code << 1), (*currentRoot).zero);
else throw "this instruction does not exist";
}
}
void addopcode(void(& instruct)(short &code), int opcode, int codeLength)
{
node *latest;
latest = &SearchTree;
for (int i = 0; i <= codeLength; i++)
{
// Add function pointer to struct if we hit the bottom.
if (i == codeLength)
{
if ((*latest).hasInst == false)
{
(*latest).instruct = &instruct;
(*latest).hasInst = true;
}
}
// Case 1
else if (opcode >> (codeLength - 1 - i) & 0b01)
{
if ((*latest).hasOne)
{
latest = (*latest).one;
}
else{
node newNode;
(*latest).one = &newNode;
(*latest).hasOne = true;
latest = &newNode;
}
}
// Case 0
else {
if ((*latest).hasZero)
{
latest = (*latest).zero;
}
else{
node newNode;
(*latest).zero = &newNode;
(*latest).hasZero = true;
latest = &newNode;
}
}
}
}
int main()
{
addopcode(ADD, 0b000011, 6);
addopcode(LDI, 0b1110, 4);
addopcode(SBRC, 0b1111110, 7);
short firstOpcode = 0b1110000000010011;
void(* instruction)(short &code) = parseOpcode(firstOpcode, &SearchTree);
instruction(firstOpcode);
return 0;
}
EDIT: I still had some #includes at the top of my file that linked to code I didn't put on StackOverflow.
The error happened because I forgot to use the new keyword and was therefor populating my search tree with local variables (which were obviously now longer around by the time I started searching through the tree).
Fixed by using:
node *newNode = new node();
(*latest).one = newNode;
(*latest).hasOne = true;
latest = newNode;
Instead of:
node newNode;
(*latest).one = &newNode;
(*latest).hasOne = true;
latest = &newNode;

Returning name of lowest node

First of all, this is part of a university course, so whilst a copy-paste solution would do, I'm looking for a bit more depth. I'll be seeing my supervisor tomorrow anyways though.
Now onto the problem. I am implementing Dijkstra's algorithm for 5 linked nodes, A-E, which have their associated costs and links stored in a vector;
struct Node
{
char nodeLink; //adjacent link
int cost; //cost of a link
}; //to use in Dijkstra algorithm
class HeadNode
{
public:
char Name;
bool Visited;
vector<Node> nodes;
HeadNode(char x) { Name = x; Visited = false; }
};
class Graph
{
char Start = 'A';
char StartNode;
char CurrentNode;
char Destination = 'E';
int TotalCost = 0;
vector<HeadNode> hnode;
vector<char> path;
vector<int> weight;
public:
Graph();
void createHeadNode(char X);
void createAdjMatrix();
char LeastDistance(char node);
void printAdjMatrix();
void Dijkstra(char StartNode);
char GetStartNode();
};
int main()
{
Graph graph;
graph.createHeadNode('A');
graph.createHeadNode('B');
graph.createHeadNode('C');
graph.createHeadNode('D');
graph.createHeadNode('E');
graph.createAdjMatrix();
//graph.printAdjMatrix();
graph.Dijkstra(graph.GetStartNode());
system("pause");
return 0;
}
Graph::Graph()
{
}
void Graph::createHeadNode(char x)
{
hnode.push_back(x);
}
In order to properly implement the algorithm, I have created a precursor function, LeastDistance(), within the class graph. I also have a function to get the start node, but that isn't particularly important here;
char Graph::LeastDistance(char node)
{
int smallest = 9999;
char smallestNode;
for (int i = 0; i < hnode.size(); i++)
{
for (int j = 0; j < hnode[i].nodes.size(); ++j)
{
if ((node == hnode[i].Name) && (hnode[i].nodes[j].cost <= smallest) && (hnode[i].Visited == false))
{
smallest = hnode[i].nodes[j].cost;
smallestNode = hnode[i].nodes[j].nodeLink;
}
else
{
hnode[i].Visited = true;
break;
}
}
}
TotalCost = TotalCost + smallest;
return(smallestNode);
}
void Graph::Dijkstra(char StartNode)
{
CurrentNode = StartNode;
if (CurrentNode == Destination)
{
cout << "the start is the destination, therefore the cost will be 0." << endl;
}
else
{
while(true)
{
if (CurrentNode != Destination)
{
CurrentNode = LeastDistance(StartNode);
cout << CurrentNode << "<-";
}
else if (CurrentNode == Destination)
{
cout << endl;
cout << "The total cost of this path is:" << TotalCost;
TotalCost = 0;//reset cost
break;
}
}
}
}
My problem is that the LeastDistance fucntion appears always to return node C, leading to it being printed over and over, so it fills the console. So far, I have tried to debug using visual studio 2017, but I cant make much sense out of the watches. I have also tweaked the order of the breaks around, and tried to make sure the visited flag is being set to true. whether any precedence of operations is affecting this I am not sure.
Thanks in advance.
I would contend that there are multiple problems with the way you implement this... but I think the one that's causing you the problem you describe is the statement right here:
if (CurrentNode != Destination)
{
CurrentNode = LeastDistance(StartNode);
cout << CurrentNode << "<-";
}
Think about what this does. Let's say your first node isn't the one you're looking for, then you call least distance and find the next smallest node. Then you print it. Then you iterate on the while loop again only to find that CurrentNode isn't the one you're looking for, so you call LeastDistance(StartNode) again, which will return the exactly same value. Thus, you'll keep printing the same result which apparently is c.
Assuming everything else is correct, I think you want:
CurrentNode = LeastDistance(CurrentNode);

Trie data structure using class C++

I am trying to implement trie data structure in C++ using class. In TrieNode class I have a TrieNode *children[26]; array and an isEndOfWord boolean value to determine if it is the end word. In that same class I have other functions appropriate to function like getters and setters and additionally insert and search.
Whenever I try to add a new word it is also setting the bool value as true at the end of each word by setting true to isEndOfWord. But in searching function it is not determining the end of the word. Please guide me as I am new to this data structure, and please comment on the way i write the code and what is the appropriate way to write it(in a Professional way, if interested). Thanks!
#include<cstdio>
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
using namespace std;
class TrieNode{
private:
TrieNode *children[26];
bool isEndOfWord;
public:
TrieNode(){
for(int i = 0; i < 26; i++){
children[i] = NULL;
}
isEndOfWord = false;
}
bool checkNull(char temp){
cout<<"\nIncheckNULL "<<temp<<" "<<(temp - 'a')<<" \n";
if(children[temp - 'a'] == NULL){
return true;
}
else{
return false;
}
}
void setNode(char temp){
cout<<"Setting node \n";
children[temp - 'a'] = new TrieNode();
}
TrieNode *getNode(char temp){
return children[temp - 'a'];
}
void setEndWord(){
this->isEndOfWord = true;
}
bool getEndWord(){
return this->isEndOfWord;
}
void insert(TrieNode*, string);
bool search(TrieNode*, string);
};
void TrieNode::insert(TrieNode *root, string key){
TrieNode *crawl = root;
//cout<<"key is "<<key<<endl;
int length = sizeof(key)/sizeof(key[0]);
//cout<<"find length\n";
for(int i = 0; key[i] != '\0'; i++){
cout<<"TEST null check key is "<<key[i]<<endl;
if(crawl->checkNull(key[i])){
cout<<"null check key is "<<key[i]<<endl;
crawl->setNode(key[i]);
crawl = crawl->getNode(key[i]);
if(key[i + 1] == '\0'){
cout<<"In setting end word\n";
if(crawl->getEndWord()){
cout<<"Word already exists";
}
else{
crawl->setEndWord();
cout<<"End word setted "<<crawl->getEndWord()<<endl;
}
}
}
else{
if(key[i + 1] == '\0'){
cout<<"In setting end word\n";
if(crawl->getEndWord()){
cout<<"Word already exists";
}
else{
crawl->setEndWord();
cout<<"End word setted\n";
}
}
else{
crawl = crawl->getNode(key[i]);
}
}
}
}
bool TrieNode::search(TrieNode *root, string key){
TrieNode *crawl = root;
cout<<"key is "<<key<<endl;
cout<<"\n In search\n";
int length = sizeof(key)/sizeof(key[0]);
for(int i = 0; key[i] != '\0'; i++){
if(crawl->checkNull(key[i])){
cout<<"INside search checknull"<<endl;
cout<<"Word does not exists"<<"sorry"<<endl;
break;
}
else{
cout<<"IN each character getting getEndWord "<<crawl->getEndWord()<<endl;
if(key[i + 1] == '\0'){
if(crawl->getEndWord()){
cout<<"Word Exists";
}
else{
cout<<"Word does not exists"<<"sorry"<<endl;
break;
}
}
else{
crawl = crawl->getNode(key[i]);
}
}
}
}
int main(){
TrieNode *root = new TrieNode();
cout<<"starting"<<endl;
root->insert(root, "hello");
cout<<"first added"<<endl;
root->insert(root, "anna");
root->insert(root, "anni");
cout<<"words added"<<endl;
root->search(root, "hello");
root->search(root, "anny");
}
Your insert and search functions can be simplified a bit.
Consider this. (Read the comments in the below code, they illustrate what the code does)
void TrieNode::insert(TrieNode *root, string key){
TrieNode *crawl = root;
if (!crawl) {
crawl = new TrieNode();
}
cout << "Adding " << key << " to the trie" << endl;
for (int index = 0, auto str_iterator = str.begin(); str_iterator < str.end(); ++str_iterator, ++index) {
char key_char = *str_iterator;
if(crawl -> checkNull(key_char)){
// If a node representing the char does not exist then make it
crawl -> setNode(key_char);
}
crawl = crawl -> getNode(key_char);
if (index == key.length() - 1) {
// We are at the last character, time to mark an end of word
crawl -> setEndWord();
}
}
}
bool TrieNode::search(TrieNode *root, string key){
TrieNode *crawl = root;
if (!crawl) {
cout << "Trie is empty!" << endl;
return false;
}
cout << "Searching for " << key << " in the trie" << endl;
for (int index = 0, auto str_iterator = str.begin(); str_iterator < str.end(); ++str_iterator, ++index) {
char key_char = *str_iterator;
if(crawl -> checkNull(key_char)){
cout << "Key is not in the trie" << endl;
return false;
}
crawl = crawl -> getNode(key_char);
if (index == key.length() - 1) {
if (!(crawl -> getEndWord())) {
cout << "Word is physically present in trie, but not present as a distinct word" << endl;
return false;
} else {
return true;
}
}
}
cout << "Code should not reach here" << endl; // IMO throw an exception I guess
return false;
}
Take advantage of the power of C++ std::string
Also your whole temp - 'a' logic is a bit iffy to me. I wouldn't much around with ASCII values unless I needed to
Why are you including a whole bunch of C headers? Just iostream should suffice to do what cstdio does.
if(!ptr) is a much more natural way to check for NULL.
In production don't use using namespace std; Instead just preface stuff like cout and endl with std::. The reason for this is to avoid polluting the standard namespace.
Read a good CPP OOP book :). It will help you a lot.
Also I lol'd at anna and anni. Your anna and anni must be proud to be in your trie :D
There are many things I'd give you feedback on, but this isn't a code review site, it's for specific questions. I'll point out briefly a few things I notice though:
1) don't include C headers; use c++ ones instead.
2) what type is string?
3) you compute length (incorrectly, assuming answer to question 2 is "the standard c++ string class"), but you don't use it.
4) search() returns a bool but you don't return anything. When you find the end of a word, you should return from the function.
5) search() calls checkNull() at the top of the for loop without ensuring that it's not null. After this: crawl = crawl->getNode(key[i]); it could be null, but then you loop and go through the pointer without testing it.
6) setNode is a public function, and unconditionally overwrites whatever is in the slot for the given variable. You can clobber an existing child if someone calls it with the same character twice and leak (and probably lose data in your tree.
7) search doesn't need to be a member of TrieNode. In fact, it doesn't access any data through "this". You probably don't want the TrieNode to be public at all, but an internal implenetation detail of Trie, which is where the search function should live, where the root should be stored and managed.
8) in c++ use nullptr instead of NULL
9) Looks like you need to debug search(), because it is not on the last letter when you check for end of word.
10) you need a destructor and need to deallocate your nodes. Or store them in unique_ptr<> for automatic deletion when your object goes out of scope.
11) don't "using namespace std;" in headers. It makes your headers toxic to include in my code.
The insert and search functions are a mess.
They use rather contrived ways to check the end of the string, duplicated unnecessarily and with a bug in one of the branches.
Here are simpler versions.
They use string size for the loop bounds, and the actions needed at the end of the loop are made after the loop, which is more natural.
void TrieNode::insert(TrieNode *root, string key){
TrieNode *crawl = root;
for(int i = 0; i < (int) (key.size()); i++){
if(crawl->checkNull(key[i])){
crawl->setNode(key[i]);
}
crawl = crawl->getNode(key[i]);
}
crawl->setEndWord();
}
bool TrieNode::search(TrieNode *root, string key){
TrieNode *crawl = root;
for(int i = 0; i < (int) (key.size()); i++){
if(crawl->checkNull(key[i])){
return false;
}
crawl = crawl->getNode(key[i]);
}
return crawl->getEndWord();
}
I used the same style, but omitted the debug outputs for readability.
Also, the code did not actually use search as a function, it didn't return a value.
Instead, it relied on debug output to show the result.
This is now corrected.
A main function complementing these is as follows.
int main(){
TrieNode *root = new TrieNode();
cout<<"starting"<<endl;
root->insert(root, "hello");
cout<<"first added"<<endl;
root->insert(root, "anna");
root->insert(root, "anni");
cout<<"words added"<<endl;
cout << root->search(root, "hello") << endl; // 1
cout << root->search(root, "anny") << endl; // 0
}

Segfault in recursive function

I'm getting a segfault when I run this code and I'm not sure why. Commenting out a particular line (marked below) removes the segfault, which led me to believe that the recursive use of the iterator "i" may have been causing trouble, but even after changing it to a pointer I get a segfault.
void executeCommands(string inputstream, linklist<linklist<transform> > trsMetastack)
{
int * i=new int;
(*i) = 0;
while((*i)<inputstream.length())
{
string command = getCommand((*i),inputstream);
string cmd = getArguments(command,0);
//cout << getArguments(command,0) << " " << endl;
if (cmd=="translate")
{
transform trs;
trs.type=1;
trs.arguments[0]=getValue(getArguments(command,2));
trs.arguments[1]=getValue(getArguments(command,3));
((trsMetastack.top)->value).push(trs);
executeCommands(getArguments(command,1),trsMetastack);
}
if (cmd=="group")
{
//make a NEW TRANSFORMS STACK, set CURRENT stack to that one
linklist<transform> transformStack;
trsMetastack.push(transformStack);
//cout << "|" << getAllArguments(command) << "|" << endl;
executeCommands(getAllArguments(command),trsMetastack); // COMMENTING THIS LINE OUT removes the segfault
}
if (cmd=="line")
{ //POP transforms off of the whole stack/metastack conglomeration and apply them.
while ((trsMetastack.isEmpty())==0)
{
while ((((trsMetastack.top)->value).isEmpty())==0) //this pops a single _stack_ in the metastack
{ transform tBA = ((trsMetastack.top)->value).pop();
cout << tBA.type << tBA.arguments[0] << tBA.arguments[1];
}
trsMetastack.pop();
}
}
"Metastack" is a linked list of linked lists that I have to send to the function during recursion, declared as such:
linklist<transform> transformStack;
linklist<linklist<transform> > trsMetastack;
trsMetastack.push(transformStack);
executeCommands(stdinstring,trsMetastack);
The "Getallarguments" function is just meant to extract a majority of a string given it, like so:
string getAllArguments(string expr) // Gets the whole string of arguments
{
expr = expr.replace(0,1," ");
int space = expr.find_first_of(" ",1);
return expr.substr(space+1,expr.length()-space-1);
}
And here is the linked list class definition.
template <class dataclass>
struct linkm {
dataclass value; //transform object, point object, string... you name it
linkm *next;
};
template <class dataclass>
class linklist
{
public:
linklist()
{top = NULL;}
~linklist()
{}
void push(dataclass num)
{
cout << "pushed";
linkm<dataclass> *temp = new linkm<dataclass>;
temp->value = num;
temp->next = top;
top = temp;
}
dataclass pop()
{
cout << "pop"<< endl;
//if (top == NULL) {return dataclass obj;}
linkm<dataclass> * temp;
temp = top;
dataclass value;
value = temp->value;
top = temp->next;
delete temp;
return value;
}
bool isEmpty()
{
if (top == NULL)
return 1;
return 0;
}
// private:
linkm<dataclass> *top;
};
Thanks for taking the time to read this. I know the problem is vague but I just spent the last hour trying to debug this with gdb, I honestly dunno what it could be.
It could be anything, but my wild guess is, ironically: stack overflow.
You might want to try passing your data structures around as references, e.g.:
void executeCommands(string &inputstream, linklist<linklist<transform> > &trsMetastack)
But as Vlad has pointed out, you might want to get familiar with gdb.