I am trying for write a hash map, but the constructor won't allocate memory, can someone help me out, I am new to code, sorry for bother you guys, but I will be really appreciated for your help.
class HashMap {
private:
HashEntry **table;
int count;
int TABLE_SIZE;
public:
HashMap()
{
TABLE_SIZE = 128;
table = new HashEntry*[TABLE_SIZE];
for (int i = 0; i < TABLE_SIZE; i++)
table[i] = NULL;
count=0;
}
}
class HashEntry
{
private:
int key;
int value;
public:
HashEntry(){}
~HashEntry(){}
HashEntry(int key, int value) {
this->key = key;
this->value = value;
}
int getKey() {
return key;
}
int getValue() {
return value;
}
void setValue(int value) {
this->value = value;
}
};
When it runs,
table = new HashEntry*[TABLE_SIZE];
the table was unable to read memory, I am newbie in coding, plz give me some help, thanks!
You could create an array of your objects via malloc(), which allows you to allocate memory dynamically. I could not test this code yet, but it should work the way it is:
HashEntry* table;
int TABLE_SIZE;
HashMap(){
TABLE_SIZE = 128;
table = (HashEntry*)malloc(sizeof(HashEntry) * TABLE_SIZE);
for(int i = 0; i < TABLE_SIZE; i++){
table[i] = NULL; //If you want to create your objects, you need to replace `NULL` with `new HashEntry()`
}
}
Related
I've found out that heap corruption error on delete[] is caused by writing somewhere where I didn't allocate anything (according to these posts: First post, Second post), the problem is though that even after trying to find the issue in this case, I am still unable to find it.
I am to create a simple database table where as a parameter of the function I get a row with data that has to correspond to the column data type.
So basically I created an array of pointers on other arrays (2d array) so that each array is row.
This is declaration for Table class:
class DLL_SPEC Table {
public:
void insert(Object** row);
void remove(int rowid);
Iterator* select();
void commit();
void close();
int getRowCount() const;
FieldObject** getFields() const;
int getFieldCount() const;
void setName(std::string name) { _nameOfTable = name; };
void setNumberOfFields(int numberOfFields) { _numberOfFields = numberOfFields; }
void setNumberOfRows(int numberOfRows) { _numberOfRows = numberOfRows; }
void setFields(FieldObject** fields) { _fields = fields; }
Iterator* select(Condition* condition) { throw 0; }
int findRowId(Condition* condition) { throw 0; }
void update(Condition* condition, std::function<void(Object**)> callback) { throw 0; }
private:
std::string _nameOfTable;
int _numberOfFields;
int _numberOfRows;
FieldObject** _fields;
Object*** _rowValues;
};
and here is the method for inserting that is causing the heap corruption error at delete[] tmpArray.
void Table::insert(Object** row)
{
Object*** tmpArray = new Object**[_numberOfRows + 1];
Object** checkedRow = new Object*[_numberOfFields];
// extend the array by 1 new row
for (size_t i = 0; i < _numberOfRows; i++)
{
tmpArray[i] = new Object*[_numberOfFields];
}
for (size_t i = 0; i < _numberOfRows; i++)
{
for (size_t j = 0; j < _numberOfFields; j++)
{
tmpArray[i][j] = _rowValues[i][j];
}
}
// check if the new row contains correct values for table
for (size_t i = 0; i < _numberOfFields; i++)
{
if (StringObject* v = dynamic_cast<StringObject*>(row[i]))
{
if (v->isType(_fields[i]->getType()))
{
checkedRow[i] = v;
}
continue;
}
if (IntObject* v = dynamic_cast<IntObject*>(row[i]))
{
if (v->isType(_fields[i]->getType()))
{
checkedRow[i] = v;
}
continue;
}
if (DoubleObject* v = dynamic_cast<DoubleObject*>(row[i]))
{
if (v->isType(_fields[i]->getType()))
{
checkedRow[i] = v;
}
continue;
}
throw std::invalid_argument("The fields of this table don't match with the data you want to enter.");
}
tmpArray[_numberOfRows + 1] = checkedRow;
_numberOfRows++;
_rowValues = tmpArray;
delete[] tmpArray;
delete[] checkedRow;
}
You allocate some space for tmpArray with
Object*** tmpArray = new Object**[_numberOfRows + 1];
at the end of the function you write to
tmpArray[_numberOfRows + 1] = checkedRow;
which writes past the end of the allocated space (subscripts run from 0 to _numberOfRows) resulting in Undefined Behavior.
Also, even if it didn't crash here, it would later because you assign tmpArray to _rowValues then delete tmpArray, leaving _rowValues dangling resulting in future issues when you dereference that pointer.
So I am trying to implement a hash table and I am having trouble seeing what is wrong in my class or constructor. In summary when I try to reach an element of hash table array, I can in constructor, but I cannot in the member function (I get seg fault), which leads me to believe there is something wrong with my class/ constructor doesn't work.
website::website(int input) //Constructor
{
SIZE = input;
node** hashtable = new node * [SIZE];
for (int i = 0; i<SIZE; i++)
{
hashtable[i] = NULL;
if(!hashtable[i])
{
cout<<"It works at "<<i<<"th"<<endl;//This is to check
}
}
}
int website::hashfunction(const char array []) //Hash function
{
int inputsize = strlen(array);
int value = 0;
for (int i=0; i< inputsize; i++)
{
value = value + int(array[i]);
}
value = value % SIZE;
return value;
}
These functions do what they are supposed to do
but when I run this function. I get seg fault at hashtable[place]==NULL level.
int website::insert(const mainentry& input)
{
int place = 0;
node*temp = new node;
/* Ignore this part
temp->data.topic = new char[strlen(input.topic)+1];
strcpy(temp->data.topic, input.topic);
temp->data.url = new char[strlen(input.url)+1];
strcpy(temp->data.url, input.url);
temp->data.summary = new char[strlen(input.summary)+1];
strcpy(temp->data.summary, input.summary);
temp->data.review = new char[strlen(input.review)+1];
strcpy(temp->data.review, input.review);
temp->data.rating = input.rating;
*/
place = hashfunction(temp->data.topic);
cout<<"Place is: "<<place<<endl; //Hash function works correctly
if (hashtable[place]== NULL) // THIS IS THE PART I GET SEG FAULT
{
hashtable[place] = temp;
temp->next = NULL;
return 1;
}
else
{
temp->next = hashtable[place];
hashtable[place] = temp;
return 1;
}
return 0;
}
Here is my class:
class website
{
public:
website(int input);
// ~website();
int insert(const mainentry & input);
int retrieve( char [], mainentry output [] );
int edit (mainentry & input);
int remove();
int display(char []);
int display_all();
int hashfunction(const char []);
private:
int SIZE;
node ** hashtable;
};
I am assuming I am making a beginner's mistake but I can't see what is going on, if anyone can direct me, I'd appreciate it.
You are shadowing the class's hashtable variable in the constructor by writing:
website::website(int input) //Constructor
{
SIZE = input;
node** hashtable = new node * [SIZE]; //<<-- Shadowing. you are declaring a local scope veriable called hastable, and not using the class's instance.
}
node** hashtable = new node * [SIZE];
should be
hashtable = new node * [SIZE];
I'm working on a programming lab on hash tables. The code we were given handles collisions by rehashing the key (by adding one) and trying again, simple, but works for lab. The problem is that, with the raw code, it could enter an infinite loop if you add a member to a full table. We were tasked to keep this from happening.
I'm using a count for contents (contentCount) so it wont get caught up in a loop, i.e. if count >= size, it won't insert.
The header and source files are below.
hashTable.h
#pragma once
#include <iostream>
using namespace std;
const int NONE = 0;
const int EMPTY = -1;
const int DELETED = -2;
class HashTable
{
public:
// Constructors
HashTable(int size);
HashTable(const HashTable & ht);
~HashTable();
// Methods
bool Insert(int key, int value);
bool Search(int key, int &value);
bool Delete(int key);
void Print();
private:
// Private methods
int Hash(int key);
int Hash2(int index);
// Private data
int Size;
int *Value;
int *Key;
int contentCount;
};
hashTable.cpp
#include "hashTable.h"
HashTable::HashTable(int size)
{
Size = size;
Value = new int[Size];
Key = new int[Size];
for (int index=0; index < Size; index++)
{
Value[index] = NONE;
Key[index] = EMPTY;
}
}
HashTable::HashTable(const HashTable & ht)
{
contentCount = 0;
Size = ht.Size;
Value = new int[Size];
Key = new int[Size];
for (int index=0; index < Size; index++)
{
Value[index] = ht.Value[index];
Key[index] = ht.Key[index];
}
}
HashTable::~HashTable()
{
delete []Value;
delete []Key;
}
bool HashTable::Insert(int key, int value)
{
if(contentCount >= Size)
{
return false;
}
// Find desired key
int index = Hash(key);
while ((Key[index] != key) && (Key[index] != EMPTY))
index = Hash2(index);
// Insert value into hash table
Value[index] = value;
Key[index] = key;
contentCount++;
return true;
}
bool HashTable::Search(int key, int &value)
{
// Find desired key
int index = Hash(key);
while ((Key[index] != key) && (Key[index] != EMPTY))
index = Hash2(index);
// Return value from hash table
if (Key[index] == key)
value = Value[index];
return (Key[index] == key);
}
bool HashTable::Delete(int key)
{
// Find desired key
int index = Hash(key);
while ((Key[index] != key) && (Key[index] != EMPTY))
index = Hash2(index);
// Delete value from hash table
if (Key[index] == key)
{
Value[index] = NONE;
Key[index] = DELETED;
contentCount--;
return true;
}
return false;
}
int HashTable::Hash(int key)
{
return key % Size;
}
int HashTable::Hash2(int index)
{
cout << "COLLISION\n";
return (index+1) % Size;
}
void HashTable::Print()
{
cout << "Index\t" << "Value\t" << "Key\n";
for (int index=0; index < Size; index++)
cout << index << "\t"
<< Value[index] << "\t"
<< Key[index] << "\n";
}
Thanks ahead for the help!
You're initializing contentCount in the copy constructor, but in HashTable(int size), you're not.
So obviously, it will be uninitialized.
This does not work. It gives an error regarding ISO C++ forbidding initialization.
class hash_map
{
private:
hash_entry **table;
const int TABLE_SIZE = 128;
public:
hash_map()
{
table = new hash_entry*[TABLE_SIZE];
for (int i = 0; i < TABLE_SIZE; i++)
table[i] = NULL;
}
int get(int key)
{
int hash = (key % TABLE_SIZE);
while (table[hash] != NULL && table[hash]->getKey() != key)
hash = (hash + 1) % TABLE_SIZE;
if (table[hash] == NULL)
return -1;
else
return table[hash]->getValue();
}
void put(int key, int value)
{
int hash = (key % TABLE_SIZE);
while (table[hash] != NULL && table[hash]->getKey() != key)
hash = (hash + 1) % TABLE_SIZE;
if (table[hash] != NULL)
delete table[hash];
table[hash] = new hash_entry(key, value);
}
~hash_map()
{
for (int i = 0; i < TABLE_SIZE; i++)
if (table[i] != NULL) delete table[i];
delete[] table;
}
};
const int TABLE_SIZE = 128;
This is the cause of the compilation error. It is allowed in C++11 only, not in C++03 and C++98.
Either make it a static member of the class, OR initialize it in the constructor. Make use of member-initialization-list for it.
Apart from that dont forget to implement copy-semantics following Rule of Three, OR disable it altogether by declaring them (don't define them) in the private section. I think, disabling it would make more sense in this case.
You need to initialize it in constructor, change
const int TABLE_SIZE = 128;
to
const int TABLE_SIZE;
and the constructor from
hash_map()
{
table = new hash_entry*[TABLE_SIZE];
for (int i = 0; i < TABLE_SIZE; i++) table[i] = NULL;
}
to
hash_map() : TABLE_SIZE(128)
{
table = new hash_entry*[TABLE_SIZE];
for (int i = 0; i < TABLE_SIZE; i++) table[i] = NULL;
}
You need to put the initialization into the constructor like this:
class hash_map
{
private:
hash_entry **table;
const int TABLE_SIZE;
public:
hash_map(): TABLE_SIZE(128)
{
table = new hash_entry*[TABLE_SIZE];
for (int i = 0; i < TABLE_SIZE; i++) table[i] = NULL;
}
...
You could have been more specific and provide a minimal example that reproduces the problem and an exact error that compiler gives you. But anyway, even without a psychic mode turned on, it is obvious that error in on this line:
const int TABLE_SIZE = 128;
You cannot initialize a class member like that, it has to be done in constructor initialization list, unless this member is a static constant compile-time expression (constexpr in C++11).
So remove = 128 from that line and modify constructor to do this:
hash_map() : TABLE_SIZE (128)
{
....
Use enumerated type:
class hash_map
{
private:
enum
{
TABLE_SIZE = 128;
};
hash_entry * table[TABLE_SIZE];
//...
};
Alright, so without going into detail on why I'm writing this class, here it is.
template<class aType>
class nArray
{
public:
aType& operator[](int i)
{
return Array[i];
}
nArray()
{
aType * Array = new aType[0];
_Size = 0;
_MaxSize = 0;
_Count = 0;
}
nArray(int Count)
{
aType * Array = new aType[Count*2]();
_Size = Count;
_MaxSize = Count * 2;
_Count = 0;
}
int Resize(int newSize)
{
aType *temp = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
temp[i] = Array[i];
}
delete[] Array;
aType * Array = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
Array[i] = temp[i];
}
delete [] temp;
_Size = newSize;
_MaxSize = newSize*2;
return 0;
}
int Push_Back(aType Item)
{
if(_Count+1 >= _Size)
{
Resize(_MaxSize);
}
Array[_Count] = Item;
_Count++;
return _Count - 1;
}
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1)
ret = 1;
return aType();
ret = 0;
return Array[Index];
}
private:
int _Size;
int _Count;
int _MaxSize;
aType * Array;
};
It is supposed to be a std::Vector type object, without all the bells and whistles.
Problem is, it doesn't seem to work.
I basically start by going
nArray<string> ca = nArray<string>(5);
ca.Push_Back("asdf");
ca.Push_Back("asdf2");
int intret = 0;
cout << ca.GetAt(1,intret);
I get an Access Violation Reading Location error and it hits on the line
Array[_Count] = Item
in the Push_back function.
The problem seems to be that it's not treating the Array object as an array in memory.
I've spent time going through the code step by step, and I don't know what else to say, it's not operating right. I don't know how to word it right. I'm just hoping someone will read my code and point out a stupid mistake I've made, because I'm sure that's all it amounts to.
Update
So now I changed 3 initializations of Array in nArray(), nArray(int Count), and Resize(int newSize)
template<class aType>
class nArray
{
public:
aType& operator[](int i)
{
return Array[i];
}
nArray()
{
Array = new aType[0];
_Size = 0;
_MaxSize = 0;
_Count = 0;
}
nArray(int Count)
{
Array = new aType[Count*2]();
_Size = Count;
_MaxSize = Count * 2;
_Count = 0;
}
int Resize(int newSize)
{
aType *temp = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
temp[i] = Array[i];
}
delete[] Array;
Array = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
Array[i] = temp[i];
}
delete [] temp;
_Size = newSize;
_MaxSize = newSize*2;
return 0;
}
int Push_Back(aType Item)
{
if(_Count+1 >= _Size)
{
Resize(_MaxSize);
}
Array[_Count] = Item;
_Count++;
return _Count - 1;
}
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1)
ret = 1;
return aType();
ret = 0;
return Array[Index];
}
private:
int _Size;
int _Count;
int _MaxSize;
aType * Array;
};
This is how my code was before. Anyway, the original problem was the fact that when I try to access a specific element in the array, it just accesses the first element, and it doesn't seem to add elements eather. It doesn't seem to be treating Array as an array.
int Resize(int newSize)
{
.
.
aType * Array = new aType[newSize*2];
At this point, instead of updating the member variable as you intended, you've actually created a local variable called Array whose value is discarded when you exit from Resize(). Change the line to
Array = new aType[newSize*2];
The same thing is happening in your constructors, they also need changing accordingly. Moreover, since the default constructor allocates an array, you should set the size members accordingly. You have too many of these: an array needs to keep track of current element count and maximum capacity, however you appear to have three members. What is the purpose of the third? Redundant information is bad, it makes code difficult to read and without a single point of truth it is easier to make mistakes.
With the code in Resize(), you can do better: the second copy is completely redundant.
int Resize(int newSize)
{
aType *temp = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
temp[i] = Array[i];
}
delete[] Array;
Array = temp;
_Size = newSize;
_MaxSize = newSize*2;
return 0;
}
Also, in
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1)
ret = 1;
return aType();
ret = 0;
return Array[Index];
}
you need curly braces around body of the if(), just indentation on its own won't do the trick:
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1)
{
ret = 1;
return aType();
}
ret = 0;
return Array[Index];
}
You have a number of problems. At a guess, the one causing problems so far is that your default ctor (nArray::nArray()) defines a local variable named Array that it initializes, which leaves nArray::Array uninitialized.
Though you probably haven't seen any symptoms from it (yet), you do have at least one more problem. Names starting with an underscore followed by a capital letter (such as your _Size, _MaxSize, and _Count) are reserved for the implementation -- i.e., you're not allowed to use them.
The logic in your Resize also looks needlessly inefficient (if not outright broken), though given the time maybe it's just my brain not working quite right at this hour of the morning.
Your array is not initialized by the constructors and resize function (working on local vars instead).
And is there a reason you want to store instances of string and not pointers to string (string *) ?
I think the answer after the changes is in moonshadow's reply:
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1)
ret = 1;
return aType();
ret = 0;
return Array[Index];
}
This code will always return aType(), the last two lines will never be reached.
You might also want to check what happens if you start out with a default-constructed nArray. (Hint: you call Resize(_MaxSize); but what is the value of _MaxSize in this case?
Edit:
This outputs "asdf2" for me as it should be (with the initialization and the braces fixed):
template<class aType>
class nArray
{
public:
aType& operator[](int i)
{
return Array[i];
}
nArray()
{
Array = new aType[0];
_Size = 0;
_MaxSize = 0;
_Count = 0;
}
nArray(int Count)
{
Array = new aType[Count*2]();
_Size = Count;
_MaxSize = Count * 2;
_Count = 0;
}
int Resize(int newSize)
{
aType *temp = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
temp[i] = Array[i];
}
delete[] Array;
Array = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
Array[i] = temp[i];
}
delete [] temp;
_Size = newSize;
_MaxSize = newSize*2;
return 0;
}
int Push_Back(aType Item)
{
if(_Count+1 >= _Size)
{
Resize(_MaxSize);
}
Array[_Count] = Item;
_Count++;
return _Count - 1;
}
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1) {
ret = 1;
return aType();
}
ret = 0;
return Array[Index];
}
private:
int _Size;
int _Count;
int _MaxSize;
aType * Array;
};
#include <string>
#include <iostream>
using namespace std;
int main()
{
nArray<string> ca = nArray<string>(5);
ca.Push_Back("asdf");
ca.Push_Back("asdf2");
int intret = 0;
cout << ca.GetAt(1,intret);
}