Seg fault at the specified line: Hash table insert/search functions - c++

I am getting a EXC_BAD_ACCESS error. I'm trying to insert words into a hash table and am using separate chaining. Here is my class Hash.h that has, within it, class wordData to store the word and pageNumbers the word appears on:
class Hash
{
private:
class wordData
{
public:
string word;
vector < int >pageNum;
wordData *nextWord;
// Initializing the next pointer to null in the constructor
wordData()
{
nextWord = nullptr;
}
// Constructor that accepts a word and pointer to next word
wordData(string word, wordData * nextWord)
{
this->word = word;
this->nextWord = nextWord;
}
// Getting and setting the next linked word
wordData *getNext()
{
return nextWord; //-------------------> BAD_ACCESS ERROR
}
void setNext(wordData * newInfo)
{
nextWord = newInfo;
}
// Setting info for the word node.
void setInfo(string & w, int pNum)
{
this->word = w;
this->pageNum.push_back(pNum);
}
// ******************* Gives a thread-bad access error************************
string getWord()
{
return word;
}
void addPageNums(int x)
{
this->pageNum.push_back(x);
}
};
private:
// Head to point to the head node of the linked list for a particular word
wordData ** head;
int size;
int *bucketSize;
int totalElements;
public:
// Class hash function functions
Hash();
// Function to calculate bucket number based on string passed
int hashFunction(string key);
// search if word is present
bool Search(string);
// Insert word
void Insert(string, int);
int bucketNumberOfElements(int index);
};
#endif /* Hash_h */
After running the debugger I found the value of nextWord to be 0x00000000000 which I understand is not the same as nullptr but is due to a NULL assignment although I can't seem to figure out where and why. I haven't included the Hash.cpp file because I think there is an obvious pointer manipulation that I'm doing wrong in the .h file.
Any help will be appreciated. Thanks.

Related

Printing all the words from a prefixtree in order

I've set up a program that can take in user input to create a prefixtree. Each character is a node which are linked together. I have a "print" command that will print the words out as the following if the user gave this input: cat, car, sat, saw:
ca(R,T),sa(T,W).
I'm trying to create two functions that will instead print out the words given from the user in alphabetical word. One function PrintAllWords() is the function that will be doing most of the work, I'm thinking of having this function be a recursive function that would print to a global string of some sort each word through push_back() then delete that current word from pull_back() and move onto the next. The second function printWordList(); would call printAllWords(); and just print out the list of words create.
I've start with some code trying to slowly get to where I want, but at the moment when I use the command "list" (the command for the new functions) my code only gives me the parent nodes C and S as the following: cs.
How can I just get the first nodes of each word, try and get the first word in the prefixtree being "cat".
My Header File:
#ifndef __PREFIX_TREE_H
#define __PREFIX_TREE_H
#include <iostream>
using namespace std;
const int ALPHABET_SIZE = 26;
class PrefixTreeNode;
/*
Prefix tree
Stores a collection of strings as a tree
*/
class PrefixTree
{
private:
PrefixTreeNode* root;
public:
//Constructs an empty prefix tree
PrefixTree();
//Copy constructor
PrefixTree(const PrefixTree&);
//Copy assignment
const PrefixTree& operator=(const PrefixTree&);
//Utility func: checks whether all characters in str are letters
bool isAllLetters(const string&) const;
//Returns the root of the prefix tree
PrefixTreeNode* getRoot() { return root; };
//Returns the root of the prefix tree
const PrefixTreeNode* getRoot() const { return root; };
//Returns whether or not the given word belongs to the prefixtree
bool contains(const string&) const;
//Adds the given word to the prefix tree
void addWord(const string&);
//Prints all of the words in the prefix tree
void printWordList() const;
//Destructor
~PrefixTree();
};
/*
Node of a prefix tree
*/
class PrefixTreeNode
{
friend PrefixTree;
private:
char c;
bool final;
PrefixTreeNode* link[ALPHABET_SIZE];
public:
//Constructs a new node
PrefixTreeNode();
//Copy constructor
PrefixTreeNode(const PrefixTreeNode&);
//Copy assignment
const PrefixTreeNode& operator=(const PrefixTreeNode&);
//Returns the character this node contains
char getChar() const { return c; }
//Returns whether this node is the end of a word
bool isFinal() const { return final; }
//Changes whether this node is the end of a word
void setFinal(bool b) { final = b; }
//Returns the node corresponding to the given character
PrefixTreeNode* getChild(char);
//Returns the node corresponding to the given character
const PrefixTreeNode* getChild(char) const;
//Adds a child corresponding to the given character
void addChild(char);
//Removes the child corresponding to the given character
void deleteChild(char);
//print all words that end at or below this PrefixTreeNode
void printAllWords() const;
//Destructor
~PrefixTreeNode();
};
ostream& operator<<(ostream&, const PrefixTree&);
ostream& operator<<(ostream&, const PrefixTreeNode&);
#endif
My Source File functions:
void PrefixTreeNode::printAllWords() const{
for (char c = 'a'; c < 'z' + 1; c++)
{
if (this->getChild(c) == nullptr)
continue;
this->getChild(c);
cout << c;
}
}
//Calls all words
void PrefixTree::printWordList() const{
PrefixTreeNode* node = root;
node->printAllWords();
}
PrefixTreeNode* PrefixTreeNode::getChild(char c)
{
if (isalpha(c))
return link[tolower(c)-'a'];
else
return nullptr;
}
void PrefixTree::addWord(const string& str)
{
PrefixTreeNode* node = root;
for (int i = 0; i < str.size(); i++)
{
if (node->getChild(str[i]) == nullptr)
node->addChild(str[i]);
node = node->getChild(str[i]);
}
node->setFinal(true);
}
We use recursion to print all the stored strings in the tree in order. Call the function from main using printAllWords(root, ""). If root points to nullptr, we return. If root->final is true, we print the word. Then we append the current character to word and loop through all it's children and call printAllWords for each of them.
The same will happen for every node.
void printAllWords(Node* current, std::string word)
{
if (current == nullptr)
return;
if (current->final)
std::cout << (word+current->c) << std::endl;
for (int i = 0; i < ALPHABET_SIZE; ++i)
printAllWords(current->link[i], word + current->c);
}
Edit: Although I must confess I'm not sure what's the use of c in the treenode. If you construct the trie such that if let's say the 2nd child (b) of the current node is not null, then that means that b is part of a trail of another word(s) through it. The following code should make it clear:
void printAllWords(Node* root)
{
string word = "";
for (int i = 0; i < ALPHABET_SIZE; ++i)
printAllWords(root->link[i], word + (char)(i + 'a'));
}
void printAllWords(Node* current, std::string word)
{
if (current == nullptr)
return;
if (final)
std::cout << word << std::endl;
for (int i = 0; i < ALPHABET_SIZE; ++i)
printAllWords(current->link[i], word + (char)(i + 'a'));
}

Solving leaky memory and syntax issues in a simple hash table

I'm implementing a basic hashtable. My logic for the table makes sense (at least to me), but I'm a bit rusty with my C++. My program returns a free memory error when I run it, but I can't seem to figure out where my problem is. I think is has to do with how I call the pointers in the various class functions.
#include <iostream>
#include <unordered_map>
#include <string>
#include <cmath>
#include <exception>
using namespace std;
int hashU(string in/*, int M*/){ //hThe hash function that utilizes a smal pseusorandom number
char *v = new char[in.size() + 1]; //generator to return an number between 0 and 50. (I arbitrarily chose 50 as the upper limit)
copy(in.begin(), in.end(), v); //First the input string is turned into a char* for use in the the function.
v[in.size()] = '\0';
int h, a = 31415, b = 27183;
for(h=0;*v!=0;v++,a=a*b%(49-1))
h = (a*h + *v)%50;
delete[] v; //Delete the char* to prevent leaky memory.
return (h<0) ? (h+50) : h; //Return number
}
struct hashNode{ //The node that will store the key and the values
string key;
float val;
struct hashNode *next;
};
struct hashLink{ //The linked list that will store additional keys and values should there be a collision.
public:
struct hashNode *start; //Start pointer
struct hashNode *tail; //Tail pointer
hashLink(){ //hashLink constructor
start=NULL;
tail=NULL;
}
void push(string key, float val); //Function to push values to stack. Used if there is a collision.
};
void hashLink::push(string key, float val){
struct hashNode *ptr;
ptr = new hashNode;
ptr->key = key;
ptr->val = val;
ptr->next = NULL;
if(start != NULL){
ptr->next = tail;
}
tail = ptr;
return;
}
struct hashTable{ //The "hash table." Creates an array of Linked Lists that are indexed by the values returned by the hash function.
public:
hashLink hash[50];
hashTable(){ //Constructor
}
void emplace(string in, float val); //Function to insert a new key and value into the table.
float fetch(string in); //Function to retrieve a stored key.
};
void hashTable::emplace(string in, float val){
int i = hashU(in); //Retrieve index of key from hash function.
hashNode *trav; //Create node traveler
trav = hash[i].start; //Set the traveler to the start of the desired linked list
while(trav!=hash[i].tail){ //Traverse the list searching to see if the input key already exists
if(trav->key.compare(in)==0){ //If the input key already exists, its associated value is updated, and the function returns.
trav->val = val;
return;
}
else //Travler moves to next node if the input key in not found.
trav = trav->next;
}
hash[i].push(in,val); //If the traveler does not see the input key, the request key must not exist and must be created by pushing the input key and associated value to the stack.
return;
}
float hashTable::fetch(string in){
int i = hashU(in); //Retrieve index of key
hashNode *trav; //Create node traveler and set it to the start of the appropriate list.
trav = hash[i].start;
while(trav!=hash[i].tail){ //Traverse the linked list searching for the requested key.
if(trav->key.compare(in)==0){ //If the the requested key is found, return the associated value.
return trav->val;
}
else
trav = trav->next; //If not found in the current node, move to the next.
}
return false; //If the requested key is not found, return false.
}
int main(){
hashTable vars; //initialize the hash table
float num = 5.23; //create test variable
vars.emplace("KILO",num);
cout<<vars.fetch("KILO")<<endl;
return 0;
}
The problem is that when you call delete[] v, you have advanced v such that it is pointing to the 0 at the end of the string, which is the wrong address to delete.
Also, you're wasting a lot of code unnecessarily copying the string out of where it is already available as a c-string.
unsigned int hashU(string in/*, int M*/) {
const char* v = in.c_str();
unsigned int h, a = 31415, b = 27183;
for(h=0;*v!=0;v++,a=a*b%(49-1))
h = (a*h + *v);
return h % 50;
}
for(h=0;*v!=0;v++,a=a*b%(49-1))
h = (a*h + *v)%50;
delete[] v; //Delete the char* to prevent leaky
You are incrementing v, then deleting an invalid memory location.

Hash table implementation in C++

I am trying the following code for Hash table implementation in C++. The program compiles and accepts input and then a popup appears saying " the project has stopped working and windows is checking for a solution to the problem. I feel the program is going in the infinite loop somewhere. Can anyone spot the mistake?? Please help!
#include <iostream>
#include <stdlib.h>
#include <string>
#include <sstream>
using namespace std;
/* Definitions as shown */
typedef struct CellType* Position;
typedef int ElementType;
struct CellType{
ElementType value;
Position next;
};
/* *** Implements a List ADT with necessary functions.
You may make use of these functions (need not use all) to implement your HashTable ADT */
class List{
private:
Position listHead;
int count;
public:
//Initializes the number of nodes in the list
void setCount(int num){
count = num;
}
//Creates an empty list
void makeEmptyList(){
listHead = new CellType;
listHead->next = NULL;
}
//Inserts an element after Position p
int insertList(ElementType data, Position p){
Position temp;
temp = p->next;
p->next = new CellType;
p->next->next = temp;
p->next->value = data;
return ++count;
}
//Returns pointer to the last node
Position end(){
Position p;
p = listHead;
while (p->next != NULL){
p = p->next;
}
return p;
}
//Returns number of elements in the list
int getCount(){
return count;
}
};
class HashTable{
private:
List bucket[10];
int bucketIndex;
int numElemBucket;
Position posInsert;
string collision;
bool reportCol; //Helps to print a NO for no collisions
public:
HashTable(){ //constructor
int i;
for (i=0;i<10;i++){
bucket[i].setCount(0);
}
collision = "";
reportCol = false;
}
int insert(int data){
bucketIndex=data%10;
int col;
if(posInsert->next==NULL)
bucket[bucketIndex].insertList(data,posInsert);
else { while(posInsert->next != NULL){
posInsert=posInsert->next;
}
bucket[bucketIndex].insertList(data,posInsert);
reportCol=true;}
if (reportCol==true) col=1;
else col=0;
numElemBucket++;
return col ;
/*code to insert data into
hash table and report collision*/
}
void listCollision(int pos){
cout<< "("<< pos<< "," << bucketIndex << "," << numElemBucket << ")"; /*codeto generate a properly formatted
string to report multiple collisions*/
}
void printCollision();
};
int main(){
HashTable ht;
int i, data;
for (i=0;i<10;i++){
cin>>data;
int abc= ht.insert(data);
if(abc==1){
ht.listCollision(i);/* code to call insert function of HashTable ADT and if there is a collision, use listCollision to generate the list of collisions*/
}
//Prints the concatenated collision list
ht.printCollision();
}}
void HashTable::printCollision(){
if (reportCol == false)
cout <<"NO";
else
cout<<collision;
}
The output of the program is the point where there is a collision in the hash table, thecorresponding bucket number and the number of elements in that bucket.
After trying dubbuging, I come to know that, while calling a constructor you are not emptying the bucket[bucketIndex].
So your Hash Table constructor should be as follow:
HashTable(){ //constructor
int i;
for (i=0;i<10;i++){
bucket[i].setCount(0);
bucket[i].makeEmptyList(); //here we clear for first use
}
collision = "";
reportCol = false;
}
//Creates an empty list
void makeEmptyList(){
listHead = new CellType;
listHead->next = NULL;
}
what you can do is you can get posInsert using
bucket[bucketIndex].end()
so that posInsert-> is defined
and there is no need to
while(posInsert->next != NULL){
posInsert=posInsert->next;
because end() function is doing just that so use end() function

find a node in a tree and replace with a new node with update private members

I am a newbie trying to learn c++. I am writing a program that is trying to count how many times a word occurs in a text field
My program is storing elements of the class word in a bintree. Word class has two private members: the string representing the word of the text file and the count. If a word already exist I have to increment the count by one
class word {
private:
string myWord;
int count;
public:
word(): myWord(""), count(1)
{
}
word(string input): myWord(input), count(1)
{
}
<ovreload operators>
<some methods>
void addCount(int oldCount)
{
count += oldCount;
}
int getCount()
{
return count;
}
};
Then in a method that will be called in main I am trying to find if the word already exist and add the count:
void removeSeparators(string input, bintree<word> &tree, int &count)
{
removeDot(input);
word * pword;
const word * currentWord;
int currCount = 0;
<use tokenizer to separate each word>
// if the tree find the word
if(tree.find(*pword) != NULL) {
//get the current word
currentWord = tree.find(*pword);
//get the current count of the word
currCount = currentWord -> getCount(); <--- ERROR line 175
pword -> addCount(currCount);
//erase the old node
tree.erase(*currentWord);
//insert new node
tree.insert(*pword);
this is the total count of words
count++; }
if(tree.find(*pword) == NULL) { tree.insert(*pword); count++; }
<bit more code for resetting tokanizer>
}
This is the error I have : countWords.cpp: In function ‘void removeSeparators(std::string, bintree<word>&, int&)’:
countWords.cpp:175: error: passing ‘const word’ as ‘this’ argument of ‘int word::getCount()’ discards qualifiers
My problem is that the find method in tree is like below and I can't change it:
const dataType* find(const dataType &findData) const
{
// this function looks for findData in the tree.
// If it finds the data it will return the address of the data
// in the tree. otherwise it will return NULL
if (root == NULL) return NULL;
else return root->find(findData);
}
How can I access the 'old' count of the word and increased by one? I am on the right track at least?
Thank you for your help!
Your getCount method should be declared const:
int getCount() const
{
...
}
This allows it to be called on const objects (such as currentWord). If a method does not alter a class's data, you should generally make it constant. This gives you more flexibility to use the const qualifier appropriately throughout your program.

File I/O in C++ - Having some trouble writing back data?

This project is a basic ATM program. I'm using a file to store all the account details. So, every time I run the .exe file, It will read the data from the file and insert it into an AVL tree. And when I close the program, all the data in the AVL nodes will be inserted back into the file.
Data is stored in the file in this order (Each separated by a newline char) ID, Password, Name, Add, City, Pin, Balance.
Sample file --
12
4576
Vert
No_999,GoLane
Dallas
89777
50000
16
2342
Nerd
No_888,FoLane
Chicago
89999
30000
The problem is I cannot write back data into the file. Any suggestions please?
P.S. Please excuse my inline class methods please...
Program--
#include<iostream>
#include<conio.h>
#include<string.h>
#include<fstream>
using namespace std;
fstream file("one2.txt",ios::in|ios::out);//Opening the file 'one2.txt' in global scope
//AVL tree code starts here
class avl
{
struct node //The structure node which is going to hold the data sets in the tree
{
int id,pwd;
char name[15],add[30],city[10];
int pn;
double bal;
node *left, *right;
int height;
//node constructors
node(int i,int p,char nam[15], char a[30], char c[10],int pin,double b, node * l,node * r,int h)
{
id=i;
pwd=p;
strcpy(name,nam);
strcpy(add,a);
strcpy(city,c);
pn=pin;
bal=b;
left=l;
right=r;
height=h;
}
node()
{
left=right=NULL;
id=pwd=pn=0;
bal=0;
height=-1;
}
};
node *root;
node *nullnode;
int Height(node *t)const //Func to return the height of a node
{
return((t==NULL)? -1:t->height);
}
int max(int a,int b)
{
return(a>b)?a:b;
}
//Beginning of Insert() -- To create and insert data into the nodes
void insert(const int &x,int p, char nam[15], char a[30], char c[10],int pin,double b, node *&t)
{
if(t==NULL)
t = new node(x,p,nam,a,c,pin,b,NULL,NULL,-1);
else if(x<t->id)
{
insert(x,p,nam,a,c,pin,b,t->left);
if(Height(t->left) - Height(t->right)==2)
{
if(x<t->left->id)
single_rotate_with_left(t);
else
double_rotate_with_left(t);
}
}
else if(x>t->id)
{
insert(x,p,nam,a,c,pin,b,t->right);
if(Height(t->right)-Height(t->left)==2)
{
if(x>t->right->id)
single_rotate_with_right(t);
else
double_rotate_with_right(t);
}
}
else
t->height=max(Height(t->left),Height(t->right)+1);
}
//End of insert()
//Func to print the node data. Just a sample to check if all the data
// were inserted into the tree
//Inorder traversal
void print(node *&t)
{
if(t!=NULL)
{
print(t->left);
cout<<endl;
cout<<"ID "<<t->id<<" Name "<<t->name;
cout<<endl<<t->pwd<<endl<<t->add<<"\n"<<t->city;
cout<<"-"<<t->pn<<endl<<t->bal<<endl;
print(t->right);
}
}
//Think there's gonna be no problem with the rotation and other AVL tree func codes.
//Beginning of AVL rotations
void single_rotate_with_left(node *&k2)
{
node *k1=k2->left;
k2->left=k1->right;
k1->right=k2;
k2->height=max(Height(k2->right),Height(k2->left))+1;
k1->height=max(Height(k1->left),(k2->height))+1;
k1=k2;
}
void single_rotate_with_right(node *&k2)
{
node *k1=k2->right;
k2->right=k1->left;
k1->left=k2;
k2->height=max(Height(k2->left),Height(k2->right))+1;
k1->height=max(Height(k1->right),(k2->height))+1;
k1=k2;
}
void double_rotate_with_left(node *&a)
{
single_rotate_with_right(a->left);
single_rotate_with_left(a);
}
void double_rotate_with_right(node *&a)
{
single_rotate_with_left(a->right);
single_rotate_with_right(a);
}
//End of AVL rotations
//Function to return the node. The 'id' variable to be searched is passed as a param
node*& search(int x,node *&t)
{
if(t->id>x)
return search(x,t->left);
else if(t->id<x)
return search(x,t->right);
else if(t->id==x)
{
return t;
}
else
return nullnode;
}
//End of search. I'm using this in the loadnode() function.
//This is where I try to write data back into the file.
void update1(node *&t,int x) // x is the control variable
{
if(x==1)
//This block will be executed only once when the function is called for the
//first time. Used to seek to the beginning of the file
{
file.seekg(0,ios::beg);
x++;
}
if(t!=NULL)// Inorder traversal in the tree
{
update1(t->left,x);
//writing the data in the same order as it was stored.
file<<t->id<<endl;
file<<t->pwd<<endl;
file<<t->name<<endl;
file<<t->add<<endl;
file<<t->city<<endl;
file<<t->pn<<endl;
file<<t->bal<<endl;
update1(t->right,x);
}
}
public:
//Avl Constructor - This one is the one which is actually used.
avl(int x,int p,char nam[15], char a[30], char c[10],int pin,double b)
{
root= new node(x,p,nam,a,c,pin,b,NULL,NULL,-1);
nullnode=new node;
}
avl()
{
root->left=root->right=NULL;
root->height=-1;
}
//Call to the private insert function
void insert1(const int &x,int p,char nam[15], char a[30], char c[10],int pin,double b)
{
insert(x,p,nam,a,c,pin,b,root);
}
//Call to the private print() function
void display()
{
cout<<endl;
print(root);
}
//Function to write a new value for 'bal' variable to a node.
//I'm actually using this to update a node anconfirm whether the value of the updated node
//is reflected back at the node
void loadnode(int x)
{
node *&t=search(x,root);
cout<<"\nLoaded node...\n";
cout<<t->id;
cout<<" "<<t->name;
t->bal=40000;
cout<<"\nUpdated Bal.."<<t->bal;
}
void update()
{
//file.seekp(0);
update1(root,1);
}
};//End of AVL Class
main()
{
cout<<"The output..\n";
int i, p, pn;
char n[15],a[30],c[10];
double b;
int prev_id=0;
file>>i>>p>>n>>a>>c>>pn>>b;
prev_id=i;
avl list(i,p,n,a,c,pn,b);
while(file)
{
file>>i>>p>>n>>a>>c>>pn>>b;
if(prev_id!=i)
// I'm using this because i got a weird scenario in which the last record was repeated twice.
{
list.insert1(i,p,n,a,c,pn,b);
}
prev_id=i;
}
cout<<endl<<"The elements in AVL tree are...\n\n";
list.display();
list.loadnode(12);//12 is the id i used for one of my records.
//Calling to write back the data into the file.
list.update();
file.close();
getch();
return 0;
}
//End of program
If file.good() returned false, some previous operation on the file failed (maybe even a read operation) and raised one of the error flags of the file object. An ugly way to solve it is to use file.clear() which will clear the error flag and allow next actions to execute successfully. A better way to solve it will be to check after each operation if there's an error (file.good() is false) and understand why this operation fails and fix it.
call seekp() to move the write pointer to the begining of the stream (fstream). seekg() moves the get pointer - not going to help when writing...