Constructor doesn't update class member variables - c++

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];

Related

How should I initialize linked list in C++? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 12 months ago.
Improve this question
I have an array which I have to initialize into a list
What I try to do
#include <stdio.h>
#include <string.h>
struct data_t
{
unsigned int id_;
char name_ [50];
};
struct node_t
{
node_t * next_;
data_t data_;
};
void initialize(node_t **, const char **, const unsigned int);
int main()
{
node_t * first = NULL;
const char * data [3] = {"Alpha", "Bravo", "Charlie"};
initialize(&first, data, 3);
return 0;
}
void initialize(node_t ** head, const char ** data, const unsigned int n) {
node_t * current = NULL;
node_t * previous = NULL;
for (size_t i = 0; i < n; i++)
{
current = new node_t;
current->next_ = previous;
current->data_.id_ = i+1;
strcpy(current->data_.name_, data[i]);
if (i == 1)
{
*head = previous;
previous->next_ = current;
} else {
previous = current;
}
}
};
next_ just loops and changes between 2 values. I tried many different options but nothing works. Please help.
Why is this happening?
You need to do something special in the case of 'first' vs 'not first', you knew this but had it wrong.
On the first one (i==0) you need to set head so the caller gets the pointer to the first node
on subsequent ones you have to set the prior ones next pointer to point at current. For the first one there is no prior
Plus you set the current->next to point to previous, thats wrong too, that made your loop
So this is what you need
for (size_t i = 0; i < n; i++)
{
current = new node_t;
current->next_ = NULL; <<<======
current->data_.id_ = i + 1;
strcpy(current->data_.name_, data[i]);
if (i == 0)
*head = current;
else
previous->next_ = current;
previous = current;
}
Since you can't use std::strings, I suggest that you add a constructor to data_t that can copy the char array:
struct data_t {
data_t(unsigned id, const char* name) :
id_{id} // can be copied automatically
{
// the char array needs to be copied manually:
std::strncpy(name_, name, sizeof name_ - 1);
name_[sizeof name_ - 1] = '\0';
}
unsigned int id_;
char name_[50];
};
With that, your initialize function could be simplified to
// last in `data`, first in the list:
void initialize(node_t*& head, const char** data, const unsigned int n) {
for (unsigned int i = 0; i < n; i++) {
// create a new `node_t` with `next_` pointing at the current `head`
// `data_` will be initialized by calling the added constructor
// assign the returned `node_t` to `head`
head = new node_t{head, {i + 1, data[i]}};
}
}
or
// first in `data`, first in the list:
void initialize(node_t*& head, const char** data, const unsigned int n) {
for (unsigned int i = n; i > 0; --i) {
head = new node_t{head, {i, data[i - 1]}};
}
}
Note that initialize takes head by reference (&) to make calling it simpler:
int main() {
node_t* first = nullptr;
const char* data[3] = {"Alpha", "Bravo", "Charlie"};
initialize(first, data, 3); // not &first here
}
Demo

C++ structures containing structures SIGSEGV

Let me paste the code first
#include <iostream>
#include <algorithm>
#define MAX 100
using namespace std;
int index;
struct node{
int key;
struct node *up;
int rank;
};
struct edge{
struct node *start, *end;
int weight;
};
struct graf{
struct node *tops[MAX];
int topsAmount;
struct edge *edges[MAX];
int edgesAmount;
};
void makeSet(struct node *z, int key){
z->up = z;
z->rank = 0;
z->key = key;
}
struct node *findSet(struct node *x){
if(x!=x->up)
x->up = findSet(x->up);
return x->up;
};
struct node *returnPath(struct node *x){
cout<<"klucz: "<<x->key<<" ranga: "<<x->rank<<endl;
if(x!=x->up)
{
returnPath(x->up);
}
}
void link(struct node *x, struct node *y){
if(x->rank>y->rank)
{
y->up=x;
}
else
{
x->up=y;
if(x->rank == y->rank)
y->rank++;
}
}
void unionFun(struct node *x, struct node *y){
link(findSet(x), findSet(y));
}
bool acompare(edge lhs, edge rhs) { return lhs.weight < rhs.weight; }
struct edge *MSTKruskal(struct graf *G){
struct edge *A = new edge[MAX];
index=0;
for(int i=0; i<G->topsAmount; i++)
{
makeSet(G->tops[i],0);
}
sort(G->edges[0], G->edges[G->edgesAmount-1], acompare);
for(int i=0; i<G->edgesAmount; i++)
{
if(findSet(G->edges[i]->start) != findSet(G->edges[i]->end))
{
A[index].start = G->edges[i]->start;
A[index].end = G->edges[i]->end;
A[index].weight = G->edges[i]->weight;
index++;
unionFun(G->edges[i]->start, G->edges[i]->end);
}
}
return A;
}
int main()
{
struct node *values[11];
for(int i=0; i<10; i++)
{
values[i] = new node;
makeSet(values[i],i);
}
unionFun(values[0], values[1]);
unionFun(values[2], values[3]);
unionFun(values[1], values[2]);
unionFun(values[5], values[6]);
unionFun(values[7], values[8]);
unionFun(values[3], values[5]);
unionFun(values[0], values[7]);
for(int i=0; i<10; i++)
{
cout<<"sciezka klucza "<<i<<endl;
returnPath(values[i]);
}
struct graf *Graf = new graf;
for(int i=0; i<10; i++)
{
Graf->tops[i] = values[i];
Graf->topsAmount++;
}
struct edge *Edges = new edge[4];
Edges[0].start = values[1];
Edges[1].start = values[2];
Edges[2].start = values[3];
Edges[3].start = values[4];
Edges[0].end = values[5];
Edges[1].end = values[6];
Edges[2].end = values[7];
Edges[3].end = values[8];
Edges[0].weight = 10;
Edges[1].weight = 12;
Edges[2].weight = 11;
Edges[3].weight = 13;
Graf->edges[0] = Edges[0]; //this line was deleted after I found out that I can't compile it
Graf->edges[0]->weight = 0;
return 0;
}
I want to set new graf so firstly in for loop I add tops to my structure and it works then I want to add edges and problem appears. I thought I can just create another array of structures edge and then just set same array in Graf on same values (Graf->edges[0] = Edges[0]; last lines of the code) but it didn't compile, so I wanted to set every value of structure edge in array Graf separately (start = start, end = end etc) but debugger shows SIGSEGV on last line (Graf->edges[0]->weight = 0;) how can I fix it?
Edges[0] has type edge, but Graf->edges[0] has type edge*, i.e. the types are incompatible, which is why the assignment is not allowed.
You probably want to take the address of Edges[0] like so:
Graf->edges[0] = &Edges[0];

How to create a linked list in C++?

I got these two structs
struct CamelZombie{
int hp;
int attack;
CamelZombie *next;
};
struct list_of_cz{
CamelZombie *head;
};
I've made a function to create linked list with given value:
void createCamelZombie(list_of_cz *&pZ, int z_hp, int z_attack, int N){
pZ = new list_of_cz;
pZ->head->hp = z_hp;
pZ->head->attack = z_attack;
CamelZombie *temp1 = pZ->head;
CamelZombie *temp2 = NULL;
for (int i = 0; i < N - 1 ; i++){
temp2 = new CamelZombie;
temp2->hp = z_hp;
temp2->attack = z_attack;
temp1->next = temp2;
temp1 = temp2;
}
}
Then i put it in function main like this, but then the propram crashed, don't know why.
list_of_cz *pZ = NULL;
createCamelZombie(pZ, z_hp, z_attack, N);
while (pList->head != NULL && pZ != NULL){
atPlant(numPlant(pList) - 1, pList)->hp -= pZ->head->attack;
if (atPlant(numPlant(pList) - 1, pList)->hp <= 0) deletePlant(numPlant(pList) - 1, pList);
int count = 0;
CamelZombie *z_temp;
z_temp = pZ->head;
while (z_temp){
if (count == 0) z_temp->hp -= allPlantAttack(pList, numPlant(pList) - 1);
else z_temp->hp -= allLaserAttack(pList); //trouble right here
if (z_temp->hp <= 0) deleteCamelZombie(pZ, count);
z_temp = z_temp->next;
count++;
}
Seem like i miss something when writing void createCamelZombie() 'cause the compiler tells me that z_temp->hp don't have a value. Please help me!
Preferably use an existing container like std::vector or std::list
#include <iostream>
#include <string>
#include <list>
struct CamelZombie{
std::string name; //added for demonstration purposes
int hp;
int attack;
//pointer to next zombie not required
};
std::list<CamelZombie> createCamelZombie2(int z_hp, int z_attack, int N) {
std::list<CamelZombie> result;
for (int i = 0; i < N; i++){
CamelZombie newZombie;
newZombie.name = "Zombie"+std::to_string(i);
newZombie.hp = z_hp;
newZombie.attack = z_attack;
newZombie.next = NULL;
result.push_back(newZombie);
}
return result;
}
Use the code like this.
int main() {
std::list<CamelZombie> listOfZombies2 = createCamelZombie2(10,20,10);
for(std::list<CamelZombie>::iterator list_iter = listOfZombies2.begin();
list_iter != listOfZombies2.end(); list_iter++)
{
std::cout<<list_iter->name<<std::endl;
}
}
If you really want to use your own linked list try the code below.
A seperate struct (list_of_cz) for the list is not required. Each zombie links to the next zombie. So just keep a pointer to the first zombie.
createCamelZombie function returns a pointer to the first zombie in the list (no need to use the function parameter (list_of_cz *&pZ) to get the zombie list)
Too many underscores and Z makes the code hard to read.
If you use pointers you need to clean up memory yourself.
.
struct CamelZombie{
std::string name; //added for demonstration purposes
int hp;
int attack;
CamelZombie *next;
};
CamelZombie* createCamelZombie(int z_hp, int z_attack, int N){
CamelZombie *result = NULL;
CamelZombie *work = NULL; //keep track of the last node in the list
for (int i = 0; i < N; i++){
//create new zombie
CamelZombie *newZombie = new CamelZombie();
newZombie->name = "Zombie"+std::to_string(i);
newZombie->hp = z_hp;
newZombie->attack = z_attack;
newZombie->next = NULL;
if (result==NULL) {
result = newZombie;
work =result;
} else {
work->next = newZombie;
work = newZombie;
}
}
return result;
}
Example of how to use the code.
int main() {
CamelZombie *listOfZombies = createCamelZombie(10,20,10);
CamelZombie *work = listOfZombies;
// print zombie names to screen ---------
while (work!=NULL) {
std::cout << work->name << std::endl;
work = work->next;
}
And free memory.
work = listOfZombies;
while (work!=NULL) {
CamelZombie *temp =work->next;
delete work;
work = temp;
}

Why my constructor can not allocate memory

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()`
}
}

qsorting an array of class pointers

I've read a lot of material on how to do this. Unfortunately, they all resort to using something other than qsort (sort, usually). However, this is impossible for me as I'm not allowed to use anything from the algorithm library. I have to implement this from scratch, pretty much. What I've got:
class String {
public:
char* string;
int size;
String(char* string=0, int size=0) {
this->string = string;
this->size = size;
}
~String() {
delete [] string;
}
};
int compare(void* obj1, void* obj2) {
String* str1 = ((String*) obj1)->getColumn(column);
String* str2 = ((String*) obj2)->getColumn(column);
int i = strcmp(str1->string, str2->string);
delete str1;
delete str2;
return i;
}
class ArrayList {
int count;
int arraySize;
public:
String** list;
ArrayList() {
count = 0;
arraySize = 10;
list = new String*[arraySize];
}
~ArrayList() {
while(size()) {
delete remove();
}
}
void add(String* s) {
if(count==arraySize)
grow();
list[count++] = s;
}
String* remove() {
return list[count--];
}
String* get(int i) {
return list[i];
}
int size() {
return count;
}
private:
void grow() {
String** temp = new String*[arraySize*=2];
for(int i=0; i<count; i++) {
temp[i] = list[i];
}
delete [] list;
list = temp;
}
};
And my (current) call to qsort, though I've tried many combinations:
qsort(list->list, list->size, sizeof(String**), compare);
The error I ALWAYS get, not matter what I pass:
argument of type ‘int (ArrayList::)()’ does not match ‘size_t’
The code I've copied here doesn't include everything, but I've verified that all of the pieces work as intended, so don't worry about missing methods and such.
You have used list->size instead of list->size(). The code should be:
qsort(list->list, list->size(), sizeof(String**), compare);