I am trying to make a simple linked list from scratch that is used by another class.
The error seems to be that sometimes the Head is not set to NULL.
I say sometimes before it does not seg fault all the time. The times that it does not seg fault, it goes to the else statement. Note I am only adding 1 string. Maybe you guys can spot something I am not seeing, cheers!
LinkedList.h:
#include <string>
#include "Link.h"
using namespace std;
class LinkedList {
Link *head;
public:
LinkedList();
void addFront(string key);
void printList();
//void addBack(string *);
};
LinkedList.cpp:
#include <cstring>
#include <string>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include "LinkedList.h"
using namespace std;
LinkedList::LinkedList() {
head = NULL;
}
void LinkedList::addFront(string key) {
//creates the new list segment
Link *l = new Link(key);
cout << "Made new Link " << key << endl;
// if the list is empty
if (head == NULL){
cout << "Going to set Head " << key << endl;
head = l;
cout << "Set Head to new link " << key << endl;
}
else {
cout << "Else statement " << key << endl;
l->setNext(head);
head = l;
}
}
void LinkedList::printList() {
//Check if list is empty
if(head == NULL)
cout << "NULL" << endl;
else {
Link *l = head;
for(;l != NULL; l=l->getNext())
cout << l->getValue() << endl;
}
}
// void LinkedList::addBack(string *f) {
// Link *l = new Link(f);
// }
Link.h
#include <cstdlib>
#include <cstring>
#include <string>
using namespace std;
class Link {
string key;
Link *next;
public:
Link(string key);
void setValue(char);
void setNext(Link *next);
string getValue();
Link *getNext();
void printList();
};
Link.cpp
#include <cstdlib>
#include <string>
#include <iostream>
#include "Link.h"
using namespace std;
Link::Link(string key) {
this->key = key;
next = NULL;
}
void Link::setNext(Link *l) {
cout << "setting new link "<<endl;
next = l;
cout<< "New link was set" << endl;
}
string Link::getValue() {
return key;
}
Link *Link::getNext() {
return next;
}
Hash.h
#include <iostream>
#include <cstring>
#include <string>
#include "LinkedList.h"
using namespace std;
class Hash{
//100 slot array for hash function
LinkedList *hashFN[100];
//preset prime number
int prime = 101;
int key;
unsigned int location;
public:
//Note: Both the key & values are the same
void insert(string key, string value);
// void deleteItem(int key);
// char* find(int key);
};
Hash.cpp:
#include <iostream>
#include <cstring>
#include <string>
#include "Hash.h"
using namespace std;
void Hash::insert(string k, string v){
//Get Hash for argv[2] aka value
size_t key = std::hash<string>()(k);
unsigned int location;
//check 1
cout << "Hash: " << key << endl;
//Find location
location = key % prime;
//check 2
cout << "Mod 101 Hash: " << location << endl;
hashFN[location]->addFront(k);
cout << "Success!" << endl;
}
// void Hash::deleteItem(int key){
// return;
// }
// char* Hash::find(int key){
// return;
// }
main.cpp
#include <iostream>
#include <functional>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include "Hash.h"
using namespace std;
int main(int argc, char *argv[]) {
Hash HashTable;
string Insert = string("insert");
string Delete = string("delete");
string Find = string("find");
string Argv(argv[2]); //Makes the argv[2] into string type
// check for Request & string parameters
if(argc != 3) {
cout << "Run program with 2 parameters. [Lower Case]" << endl;
cout << "[1] insert, find, or delete" << endl;
cout << "[2] string" << endl;
exit(1);
}
//Check for "insert"
if(strcmp(argv[1], "insert") == 0) {
HashTable.insert(Argv, Argv);
}
return 0;
}
Your immediate problem: Your linked list array in your hash table is a pointer array. Declared as:
You never seem to allocate any of these objects. so you just have a pointer array of 100 indeterminate pointers to garbage. Either allocate them, or better still, just instance them directly:
This will require you change the references to them, such as
Becomes this:
Next, you’re using non-const member variable
primeas the modulus of the hash function. Since this is hard-coded to101, your table needs to be the same size. (and in fact, I’d lose the member variable entirely and just a static const in your Hash.cpp file as far as that goes). But apart from that, the issue still remains. Your table is one slot too small. Your modulo can be from0..100, which means you need a table[101]in size to address all those slots. Remember, arrays in C/C++ are[0...(n-1)]addressed for an array of sizenSo at least declare your table like so:
Last thing I’m posting. Your linked list leaks like the Titanic. You need to clean up all those nodes when the list is destroyed. Declare a destructor in your class:
And implement it like this in your .cpp file:
OK. I lied. One more thing, Until you are comfortable in both reading and understanding the Rule of Three, you should make your class non-copyable. Put the following in a private section of your LinkedList class declaration:
This will hide the things that can cause you major issues until you are ready to implement them properly. If you find yourself with an “error of something to the effect of “cannot access private member
LinkedList(const LinkedList&)” then you’re trying to make a copy, and without proper protection of your head head pointer thats a no no. read the Rule of Three.The rest I leave to you.
Note: There are ways of doing a LOT of this easier using the standard library (
std::vector<>,std::unordered_map<>, etc.) In fact,std::unordered_map<>is a drop-in replacement for all of this. But if you’re just interested in working with the language to get familiar again, its not bad to get down to the bare metal for awhile. Just focus on relearning, then learn to use all that beautiful code the standard library has to offer.