I have a program in C that creates a hash table.
memset is Okay but, i want to initialize with for loop.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define HSZ 127
#define HASHING(x) ((x)%HSZ)
struct node_t{
int val;
struct node_t *next;
};
struct node_t *hash_table[HSZ];
void init(void){
int i;
//memset(hash_table,0,sizeof(hash_table));
for(i=0; i<HSZ; i++){
hash_table[i]->val = 0;
hash_table[i]->next = NULL;
}
}
void insert_hash(int value){
int key = HASHING(value);
struct node_t *newNode = (struct node_t*)malloc(sizeof(struct node_t));
newNode->val = value;
newNode->next = NULL;
if(hash_table[key] == NULL){
hash_table[key] = newNode;
} else {
newNode->next = hash_table[key];
hash_table[key] = newNode;
}
}
int delete_hash(int value){
int key = HASHING(value);
if (hash_table[key] == NULL)
return 0;
struct node_t *delNode = NULL;
if (hash_table[key]->val == value){
delNode = hash_table[key];
hash_table[key] = hash_table[key]->next;
} else {
struct node_t *node = &hash_table[key];
struct node_t *next = hash_table[key]->next;
while (next){
if (next->val == value){
node->next = next->next;
delNode = next;
break;
}
node = next;
next = node->next;
}
}
return 1;
free(delNode);
}
void PrintAllHashData()
{
printf("###Print All Hash Data###\n");
for (int i = 0; i < HSZ; i++){
if (hash_table[i] != NULL){
printf("idx : %d ", i);
struct node_t *node = hash_table[i];
while (node->next){
printf("%d ", node->val);
node = node->next;
}
printf("%d\n", node->val);
}
}
}
int main(void){
init();
insert_hash(1);
insert_hash(3);
insert_hash(128);
PrintAllHashData();
}
look at this code.
for(i=0; i<HSZ; i++){
hash_table[i]->val = 0;
hash_table[i]->next = NULL;
}
The IDE I am using does not throw up a compilation error when I compile the code, but during the execution the code faults and is terminated/haulted. I tried debugging the code, it faults at this line and is stopped, I think BAD ACCESS points to Segmentation Error.
then, I changed this line to
for(i=0; i<HSZ; i++){
hash_table[i].val = 0;
hash_table[i]->next = NULL;
}
but, then I got the compilation error stating 'structure type require instead of 'struct node_t *'
I think that I don't understand clearly about struct in C.
How to fix this problem?
What you are dealing with is Undefined Behavior.
See, struct node_t *hash_table[HSZ];
So, hash_table is an array of HSZ (127) pointers of the data type struct node_t.
When you do,
for(i=0; i<HSZ; i++){
hash_table[i]->val = 0;
hash_table[i]->next = NULL;
}
hash_table[0] to hash_table[126] pointers are not pointing to anything.
So, each of them (or all of them) should be initialized first to point to an object of the type struct node_t and then you can initialize them. For that matter, Using a memset does not cause a problem because memset is filling the contents of the pointers with all zeros. There is difference between filling the pointers with all zeros and filling all zeros to the memory pointed by pointers.
Trying this,
for(i=0; i<HSZ; i++){
hash_table[i].val = 0;
hash_table[i]->next = NULL;
}
is plain wrong.
To fix the issue you are facing, you need to allocate memory dynamically using malloc. You can do the in your for loop.
for(i = 0; i < HSZ; i++)
{
//Allocate memory of the size struct_node_t
hash_table[i] = malloc(sizeof(struct node_t)); //Do not cast!
//Check if memory is allocated
if(hash_table[i] == NULL)
{
//Memory not allocated, set some error state to handle and break
break;
}
//Initialize to zero
hash_table[i]->val = 0;
hash_table[i]->next = NULL;
}
struct node_t{
int val;
struct node_t *next;
};
struct node_t *hash_table[HSZ];
when you have *hash_table[HSZ], this varible hash_table is a pointer. so whatever your action is , use hash_table-> ,syntax for pointer, mean point to somewhere.
a suggestion that when you use pointer you should always allocate memory hash_table[i] = malloc(sizeof(struct node_t));
struct node_t hash_table;
but if you initilize your varible like this, you can use hash_table.val = 0
so the way of assign value depend on how you declare your varibles
struct node_t *hash_table[HSZ];
gives you an array of pointers that are unset (i.e. not pointing to anything)
void init(void) {
int i;
// memset(hash_table,0,sizeof(hash_table));
for (i = 0; i < HSZ; i++) {
hash_table[i]->val = 0;
hash_table[i]->next = NULL;
tries writing to your invalid pointers which gives undefined behavior.
Either make the array an array of structs (instead of pointers):
struct node_t hash_table[HSZ];
...
/* note use of . instead of -> since we have structs not pointers */
hash_table[i].val = 0;
or allocate the necessary structs so the array points to something:
for (i = 0; i < HSZ; i++) {
hash_table[i] = malloc(sizeof(struct node_t));
hash_table[i]->val = 0;
hash_table[i]->next = NULL;
}
Related
Can anybody explain why my hash table program for strings is just printing the letter i in the first array instead of Ben? I do not specify i anywhere so am extremely puzzled as to why this result is showing:
I have correctly set my datatypes to char with the appropriate array lengths specified, so why is it that the string is not recognised?
Code:
#include<stdio.h>
#include<stdlib.h>
#define size 7
struct node
{
char data;
struct node *next;
};
struct node *chain[size];
void init()
{
int i;
for(i = 0; i < size; i++)
chain[i] = NULL;
}
void add(char name[])
{
//create a newnode with value
struct node *newNode = malloc(sizeof(struct node));
newNode->data = name[10];
newNode->next = NULL;
//calculate hash key
char key = name[10] % size;
//check if chain[key] is empty
if(chain[key] == NULL)
chain[key] = newNode;
//collision
else
{
//add the node at the end of chain[key].
struct node *temp = chain[key];
while(temp->next)
{
temp = temp->next;
}
temp->next = newNode;
}
}
/*
* return 1, search found
* return 0, Otherwise
*/
int search(int name)
{
char key = name % size;
struct node *temp = chain[key];
while(temp)
{
if(temp->data == name)
return 1;
temp = temp->next;
}
return 0;
}
void print()
{
int i;
for(i = 0; i < size; i++)
{
struct node *temp = chain[i];
printf("chain[%d]-->",i);
while(temp)
{
printf("%c -->",temp->data);
temp = temp->next;
}
printf("NULL\n");
}
}
int main()
{
//init array of list to NULL
init();
add("Ben");
print();
printf("Searching element 10\n");
if(search(10))
printf("Search Found\n");
else
printf("Search Not Found\n");
return 0;
}
Result:
chain[0]-->i -->NULL
chain[1]-->NULL
chain[2]-->NULL
chain[3]-->NULL
chain[4]-->NULL
chain[5]-->NULL
chain[6]-->NULL
Searching element 10
Search Not Found
Syntactically your code is good.
The error is, that you call add() like this:
add("Ben");
This means that the address of a 4 character array (exactly: the address of its first member) is given to add(). The 4 characters are:
'B'
'e'
'n'
'\0'
Now in add() you read from the 11th character of the address given, at the offset of 10:
newNode->data = name[10];
This is called "out of bounds" and in Java (because you seem to know that) will throw an IndexOutOfBoundsException. But C doesn't have such checks and so the code reads whatever is there. In your example it is an 'i' by accident.
I'm attempting some homework and not sure where to go from here, or if I'm on the right path to doing this correctly. This program was given to me with the goal of creating a function to create a new node with an array large enough to hold the input "count". From there I assume I'm supposed to output the created node.
I've tried setting up the node multiple ways with different pointers, I'm not sure how to initialize the 'newnode' correctly though. And every time I try to use the input 'count' such as 'newnode->array_length = count;' I get a segmentation fault, I don't understand why though, if count is input into the function, isn't it usable in the scope of it?
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<assert.h>
typedef struct node {
struct node* previous;
struct node* next;
int array_length;
int* values;
} node;
//creates a new node with an array large enough to hold `count` values
node* create_node(int count) {
//your code here:
node* newnode;
newnode = (node*) malloc(sizeof(node));
newnode->array_length = count;
newnode->values;
newnode->next=NULL;
newnode->previous=NULL;
return newnode;
}
void append(node* a, node* b) {
assert(a);
assert(b);
a->next = b;
b->previous = a;
}
int main() {
node* a = create_node(10);
assert(a->array_length == 10);
assert(a->next == NULL);
assert(a->previous == NULL);
node* b = create_node(20);
assert(b->array_length == 20);
assert(b->next == NULL);
assert(b->previous == NULL);
append(a, b);
assert(a->next == b);
assert(b->previous == a);
assert(a->previous == NULL);
assert(b->next == NULL);
for(node* cur = a; cur != NULL; cur = cur->next) {
for(int i = 0; i < cur->array_length; i++) {
cur->values[i] = i;
}
}
}
Compilation Errors:
problem2.c: In function ‘create_node’:
problem2.c:20:30: warning: implicit declaration of function ‘size’ [-Wimplicit-function-declaration]
newnode->values = malloc(size(int) * count);
^~~~
problem2.c:20:35: error: expected expression before ‘int’
newnode->values = malloc(size(int) * count);
^~~
You're not allocating memory for values. It's set by default to whatever memory was there before, which was probably an invalid pointer. This would cause a segfault when you tried to access values.
//creates a new node with an array large enough to hold `count` values
node* create_node(int count) {
//your code here:
node* newnode = malloc(sizeof(node));
newnode->array_length = count;
newnode->values = malloc(sizeof(int) * count); // malloc memory for values
newnode->next = NULL;
newnode->previous = NULL;
return newnode;
}
I'm dealing with implementing a hash table. My understanding of a hashtable is that is that to have an array like table where you're able to access the elements quickly by getting the hash value and modding it by the table size. So my initial thought was declaring
Node *hTable [100];
where
typedef struct node {
char *s;
int value;
} Node;
and going to the index of the array and malloc a new element that belongs there. But, the problem is that I need to grow my table.
So, my question is, how would I make a dynamic table, but access it like an array? (e.g table[i]).
I know that you need to call something like
Node *table = (Node*)malloc(sizeof(Node)*size);
which lets you access it like a table table[i] =... but if I did that, I can't declare a new Node in the index of the table
table[i]=(Node*)malloc(sizeof(Node));
Here's a code that I've been testing with (getting seg fault) to better give a view of the problem:
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 typedef struct node {
5 int data;
6 struct node *next;
7 } Node;
8
9
10 void main() {
11 Node **list;
12 *list = (Node*)malloc(sizeof(Node)*10);
13 for (int i = 0; i < 10; i++) {
14 list[i] = (Node*)malloc(sizeof(Node)); //problem here?
15 list[i]->data = i;
16 list[i]->next = NULL;
17 }
18 printf("printing...\n");
19 for (int i = 0; i < 10; i++) {
20 printf("%d ", list[i]->data);
21 }
22 }
Your problem is how you allocate space for list. list is uninitialized and does not point to valid memory, you must allocate space for it first, and then allocate space for each element:
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
int data;
struct node *next;
} Node;
int main() //return type of main is int
{
Node **list;
list = malloc(10 * sizeof *list); //allocate memory for list not *list, also no need to cast return value of malloc.
for (int i = 0; i < 10; i++)
{
list[i] = malloc(sizeof *list[i]); //allocate space for each element.
list[i]->data = i;
list[i]->next = NULL;
}
printf("printing...\n");
for (int i = 0; i < 10; i++)
{
printf("%d ", list[i]->data);
}
return 0;
}
It doesn't need to be an array of pointers, you can simply make an array of nodes, with:
Node *list = malloc(sizeof *list * count);
Then you can access list[i].s and list[i].value.
When you want to grow the table, you use realloc():
new_list = realloc(list, sizeof *list * new_count);
if (new_list) {
list = new_list;
} else {
// report allocation failure
}
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int data;
struct node *next;
} Node;
int main() {
// just initialize it this way ( previous was undefined behavior, dereferencing an initialize pointer)
Node **list= malloc(sizeof(Node*)*10);
for (int i = 0; i < 10; i++) {
list[i] = malloc(sizeof(Node*)); //problem here?
list[i]->data = i;
list[i]->next = NULL;
}
printf("printing...\n");
for (int i = 0; i < 10; i++) {
printf("%d ", list[i]->data);
}
}
I am trying to create a Hash Map in C. Below is the code. When I try to
assign value to the elements of Darray ( each of which is a pointer to a Node) I am getting a segmentation fault ( i.e. at line 23 and24). Could anybody help in pointing out where am I going wrong.
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node* next;
}Node;
typedef struct Map{
struct Node** Darray;
} Map;
#define SIZE 10
int main()
{
int i=0;
Map* M = malloc(sizeof(Map));
M->Darray = (struct Node**)malloc(sizeof(Node*)*SIZE);
for (i =0;i < SIZE;i++){
M->Darray[i]->data =0;
M->Darray[i]->next =NULL;
}
}
You allocate space for SIZE pointers to Node, but don't initialize these in any way, so when you access M->Darray[i] in M->Darray[i]->data you get segmentation fault because value of M->Darray[i] has not been set.
You need to allocate space for each node before using it:
for (i = 0; i < SIZE; i++) {
M->Darray[i] = malloc(sizeof(Node));
M->Darray[i]->data = 0;
M->Darray[i]->next = NULL;
}
Depending on your needs, you could also change Darray to be an array of nodes instead of node pointers, so you can allocate space for all nodes at once:
struct Node* Darray;
...
M->Darray = malloc(sizeof(Node) * SIZE);
for (i = 0; i < SIZE; i++) {
M->Darray[i].data = 0;
M->Darray[i].next = NULL;
}
I'm trying to implement sequence_insert_at using the add_to_front function here
Everything before
typedef struct sequence *Sequence;
is pasted from another c file.
void sequence_insert_at(Sequence s, int pos, int item)
{
struct node* temp = s->lst;
for(; pos > 0; --pos)
{
temp = temp->rest;
}
add_to_front(&temp, item);
++s->length;
if(!temp->rest)
{
s->end = temp;
}
//s->lst = temp;
}
I don't know why I keep getting a runtime error. if I clone s->lst and traverse the clone, I'm not modifying the pointer to the node in s, but if I change temp, s->lst should have the reflected changes since the nodes are all linked still. Any ideas as to how to fix this? I tried creating another node that is one before the temp after traversal, and then setting it->rest = temp, but that failed as well.
following mistakes a could spot but only so far to get the main function run
new_sequence does not initialize anything in Sequence it creates. lst is not initialized when you access it in sequence_insert_at
struct node* temp = s->lst;
here how it should look like
Sequence new_sequence()
{
Sequence s = malloc(sizeof(struct sequence));
if(!s)
{
printf("Out of memory. Can't allocate s\n");
exit(EXIT_FAILURE);
}
s->lst = malloc(sizeof(struct node));
if(! s->lst) {
printf("Out of memory. Can't allocate lst\n");
}
s->lst->rest = NULL;
s->length = 0;
return s;
}
also s->lst->rest has to be set to NULL, this is what tells that the list has no more elements an not end witch turns obsolete.
struct sequence
{
struct node* lst;
int length;
};
You should be passing the sequence itself to your functions not a pointer to some internal data in the sequence.
add_to_front(&temp, item);
Your sequence_insert_at function should be the one that can handle any position not add_to_front() so it is easier to call with the position 0 from add_to_front() and your having the the hole work done in one function, not a half here and a half there.
void sequence_insert_at(Sequence s, int pos, int item)
{
if(s && pos <= s->length) {
print_sequence(s);
struct node *newnode = malloc(sizeof(struct node));
if (newnode == NULL) {
printf("ERROR! add_to_front ran out of memory!\n");
exit(EXIT_FAILURE);
}
newnode->first = item;
struct node* temp = s->lst;
struct node* prv = NULL;
for(int i = 0; i < pos; i++) {
printf("skip %d\n", temp->first);
prv = temp;
temp = temp->rest;
}
newnode->rest = temp;
if(pos == 0) {
printf("insert as first\n");
s->lst = newnode;
} else {
printf("insert before %d\n", temp->first);
prv->rest = newnode;
}
++s->length;
}
}
and in add_to_front only one statement is needed
void add_to_front(Sequence s, int item) {
sequence_insert_at(s, 0, item);
}
as for inserting at the back of the list
void add_to_back(Sequence s, int item) {
sequence_insert_at(s, s->length, item);
}
A small test with the main function
void print_sequence(Sequence s)
{
struct node* temp = s->lst;
for(int i = 0; i < s->length; temp = temp->rest) {
printf("%d ", temp->first);
i++;
}
printf("\n");
}
int main()
{
Sequence derp = new_sequence();
sequence_insert_at(derp, 0, 14);
add_to_front(derp, 16);
sequence_insert_at(derp, 0, 17);
sequence_insert_at(derp, 2, 15);
add_to_back(derp, 13);
print_sequence(derp);
delete_sequence(derp);
return 0;
}
output is:
17 16 15 14 13
You'll have to go trough the other functions and fix them.
Finally i should note that variable names you have choosen are little bit confusing if not misleading, i would name them this way
typedef struct node {
int data; /* the data that a node holds */
struct node* next; /* the pointer to the next node */
} Node_t;
typedef struct sequence {
struct node* head; /* head or first element of the sequence/list */
int length; /* length is ok but size is better */
} Sequence_t;