Access Violation with HashTable - c++

I was given an assignment to create a hash table that contains 30 buckets (20 primary, and 10 overflow), with each bucket containing 3 slots (each slot containing 2 stings for key and data passed in), a counter integer and a pointer variable that points to the next overflow bucket. My last C++ class was over a year ago so I'm completely lost as to how I am supposed to create this table properly (with no help from my professor).
This is my class declaration below. It technically compiles, however it crashes immediately, and when it debugs, I get an "Access Violation Reading Location" error stating "this was nullptr" on my home computer (and it includes a specific memory location on the computer I used in class).
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
// Define Global Variables
#define MAXBUCKETs 30
#define MAXSLOTs 3
typedef char STR10[10 + 1];
typedef char STR20[20 + 1];
// Define Class
class hash{
public:
int primaryBuckets = 20;
int overflowBuckets = 10;
union bucket
{
int count;
bucket* nextOverflow;
struct slot {
string keyValue;
string dataValue;
};
slot* slots[2];
} HashTable[30];
hash(); // Initialize HashTable
int HashFunction(STR10 key, int buckets); // Hash key to index
void InsertIntoHT(STR10 key, STR20 data); // Add data to slot
void PrintItemsInIndex();
void InsertOverflow(STR10 key, STR20 data, int index);
void InsertPrimary(STR10 key, STR20 data, int index);
};
My constructor, from what I understand, initialized the array in the right order
::hash::hash()
{
for (int i = 0; i < MAXBUCKETs; i++)
{
HashTable[i].count = 0;
for (int j = 0; j < MAXSLOTs; j++)
{
HashTable[i].slots[j]->keyValue = "no_data";
HashTable[i].slots[j]->dataValue = "no_data";
}
}
}
I'm pretty desperate for help at this point. I'm almost certain it's a bad pointer, but I've never understood them well. All help will be greatly appreciated! (This is also my first post so hopefully I didn't do anything wrong)

Maybe I misunderstand this, but the union looks suspicious
union bucket
{
int count;
bucket* nextOverflow;
struct slot {
string keyValue;
string dataValue;
};
slot* slots[2];
} HashTable[30];
A union is supposed to hold only one of its members, in this case one of
count
nextOverflow
slots[2]
Maybe a struct bucket is more appropriate.
Specifically,
HashTable[i].count = 0;
sets count member to zero, and at the same time overwrites memory of slots, which holds a pointer to a slot entry
HashTable[i].slots[j]->keyValue = "no_data";
Here you must either use plain slot objects, which I recommend, e.g.
slot slots[MAXSLOTs];
or first initialize with new
for (int i = 0; i < MAXSLOTs; ++i)
slots[i] = new slot;

Related

Accessing Variables In Struct Array Outside of Scope

I am brand new to SO, and it all looks very helpful.
My code is being used for cryengine, but this seems to be a good all around c++ problem. And lets face it, the official CE forums blow.
The trouble I'm having is accessing the const char* variable of a struct array outside of the scope I'm assigning the variable in.
BuildingManager.h
class CBuildingManager {
public:
struct SBuilding {
const char* name;
};
struct SBuilding buildings[999];
//string buildingName;
const char* buildingList[999];
};
BuildingManager.cpp
void CBuildingManager::LoadBuildingXML() {
int n = -1;
const char *name;
const char *value;
//XML iterator is long and not necessary for example. n++ per iteration.
//it just works
//last part of iterator
for (size_t j = 0; j < tags->getNumAttributes(); j++) {
//Get building name in XML. This works
tags->getAttributeByIndex(j, &name, &value);
//assign building name to name in struct
buildings[n].name = value;
CryLog("%s", buildings[n].name);
buildingList[n] = buildings[n].name;
}
}
}
}
}
void CBuildingManager::LogAction(int x) {
//x modified by input. also works
CryLog("%c", buildingList[x]); //this, however, does not
}
So basically, I can print the building name as a string inside of the iterator, and it prints the whole building name (ie. "House")
But when I call LogAction, the building name will only print as a char, and will only show a single random symbol.
How can I convert the name in the struct to a string or otherwise get it to print as a whole word outside of the iterator?
Please let me know if my question is vague or shaky, and I will do my best to clean it up.
-Moose

Dynamic Polymorphic Memory Container - Return Value Incorrect

I am currently working on an dynamic memory container.
Basic idea of the class is that you should be able to get the iterator of an object if you really do not know it, without the use of a for loop throughout all the elements to boost performance. The issue I have is the following; when you pass your pointer address to the object you want to get the iterator of it type casts the object into the extended memory containers structures type. This type contains an extra element, an integer. (IteratorNum)
When following the code the integer within the function is set to correct value, as below would be 50. But when the returned value is set into the local integer used in the main function it is 200? I've been adding watches and cannot figure out how it is possible that the function returns 50 but value gets set to 200.
template <typename DataType> class MemoryContainer {
public:
struct LevelData : DataType
{
int element;
};
DataType &New()
{
elements++;
//Reallocate the size of the array
ld = (LevelData*)realloc(ld, sizeof(LevelData) * elements);
//Set the iteratorNumber
ld[elements - 1].element = elements - 1;
return ld[elements - 1];
}
DataType *reserve(int num)
{
return calloc(num, sizeof(DataType));
}
DataType &operator[](int i)
{
return ld[i];
}
bool inArray(DataType *type)
{
//Compare memory addresses and see if it's within.
return (type >= &ld[0]) && (type < &ld[elements - 1]);
}
static unsigned int getIterator(DataType *type)
{
// v this is 50, but in main says returns 200.
return ((LevelData*)type)->element;
}
MemoryContainer()
{
elements = 0;
}
~MemoryContainer()
{
free(data);
}
private:
unsigned int elements;
LevelData *ld;
};
struct Effective
{
//Set it to polymorphic classes
virtual void dummy()
{
}
char * testvar;
Effective(char * c)
{
testvar = c;
}
Effective(){}
};
MemoryContainer<Effective> myContainer;
int _tmain(int argc, _TCHAR* argv[])
{
//Create 200 elements in the array
for(int i = 0; i < 200; i++)
myContainer.New().testvar = "E";
//Add pointer for testing purposes to get the iterator.
Effective * pointer = &myContainer[50];
//Test setting it's value
pointer->testvar = "HEHEHE";
//Get iterator of our pointer in the array
unsigned int i = myContainer.getIterator(pointer);
printf(pointer->testvar);
system("PAUSE");
return 0;
}
I suspect it is the visual studio debugger getting confused between your two i variables. If you print out the value of i, it will print correctly. If you change the name of your variable to something else, the value shows as 50 in the debugger.
That said, your code is a mish-mash of c and c++ and won't work correctly with anything that requires a copy constructor. I would suggest at the very least using new [] rather than realloc.
Also, any user of this collection who tries to store a class with a member variable called element is going to get mighty confused.
The unsigned int i in the main function really has a value of 50, but the debugger is confusing it with the i declared in the for loop (I reproduced this with Visual Studio 2013). If you cout i it will be 50, and if you change the variable name it will show up as 50 in the debugger. I've never seen this problem before so I wonder if it might be due to your use of malloc/realloc/free with C++ objects.

How can I access a class's member function via an array of pointers?

I have a pretty standard class with some public member functions and private variables.
My problem originally stems from not being able to dynamically name object instances of my class so I created an array of pointers of the class type:
static CShape* shapeDB[dbSize];
I have some prompts to get info for the fields to be passed to the constructor (this seems to work):
shapeDB[CShape::openSlot] = new CShape(iParam1,sParam1,sParam2);
openSlot increments properly so if I were to create another CShape object, it would have the next pointer pointing to it. This next bit of code doesn't work and crashes consistently:
cout << shapeDB[2]->getName() << " has a surface area of: " << shapeDB[2]->getSA() << shapeDB[2]->getUnits() << endl;
The array of pointers is declared globally outside of main and the get() functions are public within the class returning strings or integers. I'm not sure what I'm doing wrong but something relating to the pointer set up I'm sure. I'm writing this code to try and learn more about classes/pointers and have gotten seriously stumped as I can't find anyone else trying to do this.
I'm also curious as to what the CShape new instances get named..? if there is any other way to dynamically create object instances and track the names so as to be able to access them for member functions, I'm all ears.
I've tried all sorts of permutations of pointer referencing/de-referencing but most are unable to compile. I can post larger chunks or all of the code if anyone thinks that will help.
class CShape {
int dim[maxFaces];
int faces;
string units;
string type;
string name;
bool initialized;
int slot;
public:
static int openSlot;
CShape();
CShape(int, string, string); // faces, units, name
~CShape();
void initialize(void);
// external assist functions
int getA(void) {
return 0;
}
int getSA(void) {
int tempSA = 0;
// initialize if not
if(initialized == false) {
initialize();
}
// if initialized, calculate SA
if(initialized == true) {
for(int i = 0; i < faces; i++)
{
tempSA += dim[i];
}
return(tempSA);
}
return 0;
}
string getUnits(void) {
return(units);
}
string getName(void) {
return(name);
}
// friend functions
friend int printDetails(string);
};
// constructor with values
CShape::CShape(int f, string u, string n) {
initialized = false;
faces = f;
units = u;
name = n;
slot = openSlot;
openSlot++;
}
My guess is you use the CShape constructor to increment CShape::openSlot?
You're probably changing the value before it's read, thus the pointer is stored in a different location.
Try replacing openSlot with a fixed value to rule out this CShape::option.
-- code was added --
I'm pretty sure this is the problem, the constructor is executed before the asignment, which means the lhs. will be evaluated after CShape::openSlot is incremented.

How to manage objects in a fixed array?

This if for my homework.
I have a class called Student that takes 3 parameters (id, name, class) and I want to store each student in an array called Roster (which can only have 7 students).
The user will provides input to add or remove students. Thus, I have to manage the array by creating or deleting students. So if the user specify the student ID, I have to remove him for the array.
I tried to use a fixed array, but I'm struggling to make it works. Is there a better way to implement this?
I must not use a vector or any STL container.
student.h
#ifndef STUDENT_H
#define STUDENT_H
#include <iostream>
#include <string>
static const int SIZE = 7;
class Student {
private:
int student_id;
std::string name;
std::string classification;
public:
Student(int, std::string, std::string); // constructor; initialize the list to be empty
~Student();
void print();
};
#endif
student.cpp
#include <iostream>
#include <string>
#include "student.h"
#define PROMPT "class> "
using namespace std;
Student::Student(int a, string b, string c){
student_id = a;
name = b;
classification = c;
}
Student::~Student(){
//delete Student
}
void Student::print(){
cout<<"Enrolled:"<<endl;
cout<<student_id<<"-"<<name<<"-"<<classification<<endl;
}
main.cpp
#include <iostream>
#include <string>
//#include <sstream>
#include "student.h"
#define PROMPT "class> "
using namespace std;
//**** Implement Error Handling ****\\
enum errorType {
UNKNOWN_ERROR,
INPUT_ERROR,
HANDLER,
NUM_ERRORS
};
// error messages
string errorMessage[NUM_ERRORS] = {
"Unknown Error\n",
"Input Error\n",
};
// error handler
void handleError(errorType err) {
if(err > 0 && err < NUM_ERRORS)
cout<< "Error: "<< errorMessage[err];
else cout<< "Error: "<< errorMessage[UNKNOWN_ERROR];
}
//**** END Error Handling ****\\
void enroll(Student newStudent){
cout<<"test";
Student roster[SIZE];
for(int i=0;i<SIZE;i++){
newStudent->roster[i];
}
}
void handleInput() {
int id; string n, c;
cin>>id>>n>>c;
Student newStudent(id,n,c);
newStudent.print();
enroll(newStudent);
//cout<<"hello3"<<endl;
return;
}
int main() {
//Student newStudent; /* <-- why doesn't this work?!*/
string input = "";
bool finished = false;
cout<<PROMPT; // prompt the user
while(!finished) {
if(input!="") cout<<PROMPT;
cin>>input;
if(input=="enroll") {
cout<<PROMPT<<"Enroll student:"<<endl;
handleInput();
}
else if(input=="drop") {
cout<<PROMPT<<"Enter ID:"<<endl;
}
else if(input=="roster") {
cout<<"This will print formatted list of students"<<endl;
}
else if(input=="quit") {
finished=true;
}
else handleError(errorType(1));
}
}
Since it is a homework, I'd like to point out some mistakes you did because it is important to understand what you are doing in the first place.
You must not program by coincidence, but by trying to understand exactly what's going on. By doing that you will become better and better and the answers should fall in place.
What you've done
So, from what you are describing, the array is fixed. Thus it is a good idea to use a constant as you did (SIZE).
However, as we can see below you a declaring an array of size SIZE in the function. By doing that, your array is like a temporary variable, because its scope is inside the function. Each time you call this function, the array will be declared again and then deleted at the exit. So it should be declared outside.
void enroll(Student newStudent)
{
cout<<"test";
Student roster[SIZE]; // Here 'roster' will be available only inside the function.
for(int i=0;i<SIZE;i++)
{
newStudent->roster[i]; // Here there is few mistakes see my explanation below*
}
}
If we look at this part:
newStudent->roster[i];
First of all, the arrow '->' is used with pointers. The dot '.' is used with objects. In both case, it does the same thing, access to public members of Student.
Since you passed
void enroll(Student newStudent)
you should use '.' instead.
newStudent.SomeOfYourMembers;
If the parameter was a pointer to a Student
void enroll(Student *newStudent)
Then, you'd have to use the arrow '->' like you did.
Back to the original statement:
newStudent->roster[i];
This means, you want to access to 'roster' array at position 'i' inside your Student object (newStudent). As you can see in your code, roster is not declared inside Student (and should not be since you want an array of Students), so that won't work.
Guidelines
As I mentionned, your array should be outside the function, so at a higher scope.
Then, if you need an array of student, basically, 'roster[i]' will give you access to the student 'i'. Thus, if you want to print the student, you would do something like that:
roster[i].print();
This would be valid because 'print()' is defined as public.
In order to store a student inside the array, you can do something like:
roster[i] = new Student(0 /* id*/, "name", "classification");
But don't forget, each time you use new, you have to balance it with a delete. And if you are creating the student like this in a loop, you will have to clean them the same way:
for(int i = 0; i < SIZE; ++i)
{
delete roster[i];
}
Good luck!
Don't hesitate if there is there anything that I could clarify. I hope this helps!
Edit: In reply to your first comment.
Concerning the roster array
No, it is not mandatory to create a class roster you could declare roster in the main.cpp.
The key concept is that by defining
Student roster[SIZE];
the array will contains objects of type Student.
What roster[i].print() means is that you are printing one of the Student of that array, in fact the one at position 'i'.
Concerning the print() function
What is powerfull with Object Oriented language, each object will have the same print() function. So, you do not need to convert the array to string.
However, if you want a string to be printed out (or returned) you can write the code inside the print() function that will do this job.
The advantage of this, is that if further on you need to change your array in some ways, your print() function will always work.
Concerning the Delete
When you are doing something like this on an array that contains objects:
delete roster[i];
It will delete the object at the position 'i'. Thus, the destructor of that Student 'i' will be called. If your object Student would contains other object, you would have to delete them in the destructor.
Further notices
Since ID is an input that you are storing into a string, you will have to convert the ID to the same type of the student_id, which is a int. Then you can always write a loop for each student and check their ID to delete the proper one.
Concerning the container, a fixed array might not be the best to achieve this job. You might want to look the LinkedList concept.
It doesn't make much sense for enroll to be a member function, so
I'd wrap the roster into a class to get automatic clean up of my
pointers.
#include <cstddef>
struct Student {};
class Roster
{
private:
static const size_t size = 7;
// non-copyable
Roster(const Roster&);
Roster& operator=(const Roster&);
public:
Roster() {
for(unsigned i = 0; i < size; ++i) {
roster_[i] = NULL;
}
}
~Roster() {
for(unsigned i = 0; i < size; ++i) {
delete roster_[i];
}
}
// enroll by copy
bool enroll(const Student& s) {
for(unsigned i = 0; i < size; ++i) {
if(roster_[i] == NULL) {
roster_[i] = new Student(s);
return true;
}
}
// out of space
return false;
}
// enroll by taking ownership
bool enroll(Student* s) {
for(unsigned i = 0; i < size; ++i) {
if(roster_[i] == NULL) {
roster_[i] = s;
return true;
}
}
// out of space
return false;
}
private:
// data
Student* roster_[size];
};
int main()
{
Roster r;
Student s;
r.enroll(s);
Student* sp = new Student();
r.enroll(sp);
return 0;
}
What about this?
Student * roster[2];
roster[0] = new Student(5,"first","2A");
roster[1] = new Student(2,"Second","5B");
Ps:
Enrol and Size shouldn't be members of the student class.
Print should ideally be externalized and a ToString function should be added instead.
You should use the inline constructor initialization instead:
Student(int a,string b,string c):id(a),name(b),class(c){}
You've used the keyword class as a variable name of type string. You shouldn't do that. Does it even compile like that?
enroll should have two arguments: void enroll( Student enrollee, Student Roster[]). You should probably change the name of Roster to roster because it's not a class and typically class names are capitalized.
If your array will only ever have 7 students then you could use some sentinel value to mark that the current student as an invalid student. Perhaps the id will be -1 to mark this. It means basically that you need some way to keep track of which spots in the array you can still use. If you don't do this then declaring an array of Students will get you an array of students with garbage member variables. You wouldn't be able to tell which students are real ones and which are just place holders for when someone new enrolls in the class. I would create a default constructor of Student and initialize its member variables like this:
id=-1;
name="";
name_of_class="";
I changed the name of your string class to avoid confusion.
After all that, enroll would look something like this:
void Student::enroll( Student enrolee, Student roster[]){
//search through roster to check for the first student with an
//id of -1
//if there are no students with id of -1, produce an error message
//that the class is full
//overwrite the student with id of -1 with the id, name, and
//name_of_class of enrollee
}
Although I'm not sure what exactly string class is there for. Does it store what class the Student is in? Is it their year in school like Freshman, Sophomore?
If you're suppose to use dynamic allocation of roster, though, it's a different story, but you said it will only ever have seven students.

Problem passing a list of objects to another class, C++

Below I have written a sample program that I have written to learn about passing a list of objects to another class. I talk about the problems I am having below.
#include <iostream>
#include <vector>
using namespace std;
class Integer_Class
{
int var;
public:
Integer_Class(const int& varin) : var(varin) {}
int get_var() { return var; }
};
class Contains_List
{
typedef Integer_Class* Integer_Class_Star;
Integer_Class_Star list;
public:
Contains_List(const Integer_Class_Star& listin) : list(listin) {}
Integer_Class* get_list() { return list; }
};
int main (int argc, char * const argv[])
{
// Create a vector to contain a list of integers.
vector<Integer_Class> list;
for(int i = 0; i < 10; i++)
{
Integer_Class temp_int(i);
list.push_back(temp_int);
}
This is where the errors start occuring. Could someone please look at the second class definition and the code below and shed some light on what I'm doing wrong. Thank you so much, as always!
// Import this list as an object into another object.
Contains_List final(list);
// Output the elements of the list by accessing it through the secondary object.
for(int i = 0; i < 10; i++)
{
cout << final.get_list()[i].get_var();
}
return 0;
}
You don't mention what sort of errors you are getting, but one very obvious problem with your code is that the constructor for Contains_List expects a pointer to Integer_Class while the parameter you are sending it (list) is of type vector<Integer_Class>.
A vector is not the same as an array, so you cannot pass it as pointer to the type it contains. Either change your constructor to accept a vector or pointer/reference to vector, or change the code that is causing you problems so that it sends it a pointer to an array.
The 'Contains_List' constructor takes in an 'Integer_Class*'
You declare 'list' to be of type 'vector', yet you pass it to the the 'Contians_List' constructor. You should change the 'Contains_List' class so that it holds a vector instead of an Integer_List array. The two are not interchangeable.
You could also change the vector to be an array of Integer_List's instead, if you so wished.