Hash table in C always yields Seg fault - c

I am trying to develop a hash table in the C Programming Language which always fails with seg fault. I am trying to do seperate chaining so I created a struct which has two properties: word and next. The word is a char* and next a pointer to the next node, eventually creating a hash table that conatains an array of linked list.
typedef struct node
{
char* word;
struct node* next;
}node;
node* table[26];
After this I am indexing into the table by using a hashing function which simply indexes into the table.
Do you have a fix?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <cs50.h>
typedef struct node
{
char* word;
struct node* next;
}node;
node* table[26];
int hash(char* key);
void index();
int main(int argc, char* argv[])
{
index();
return 0;
}
int hash(char* key)
{
int hash = toupper(key[0]) - 'A';
int res = hash % 26;
return res;
}
void index()
{
printf("Insert a word: ");
char* k = GetString();
node* predptr = malloc(sizeof(node));
node* newptr = malloc(sizeof(node));
for(int i = 0; i < 26; i++)
{
if(hash(k) == i)
{
predptr = table[0];
predptr->next = newptr;
newptr = predptr;
break;
}
else
{
}
}
}

typedef struct node
{
char* word;
struct node* next;
}node;
node* table[26];
table is an array of 26 pointers, all initialized to NULL.
Specifically table[0] is a NULL pointer and you try to dereference it
predptr = table[0];
predptr->next = newptr; // dereference NULL pointer
// NULL->next

You created a table of 26 pointers to node structure, but did not allocate memory for them. Also, it is not clear what your GetString() method does and how the memory for the strings returned by it is managed. You have to use your (incomplete) index method (provided that you properly allocate necessary objects there) instead of just calling table[ha]->word = word; which segfaults because tabel[ha] does not point anywhere.

If you are doing hashing on word then change hashing function as
int hash(char *k){
int i=0;
for (;i<strlen(k) ;++i ){
//apply hashing technique
}
}
Your table has 26 NULL pointers , when you use
predptr = table[0];
predptr->next = newptr;
here predptr become NULL and then you are looking for it's next pointer which leads to segmentation fault .
To improve index performance you don't have to search for hashed index ,just goto that index < (No of maxm entries ) and follow it's pointer if it's null then add this word here it self else follow it's next pointer .

Related

Hashing of small dictionary

I want to hash small dictionary ("dictionaries/small"). Main file compiles correctly, but at runtime it produces "Segmentation fault" message with function insert() (specifically something wrong with malloc(), but I don`t know what).
HASH.c
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <ctype.h>
#include <string.h>
typedef struct node
{
char* name;
struct node* next;
}
node;
node* first[26] = {NULL};
int hash(const char* buffer)
{
return tolower(buffer[0]) - 'a';
}
void insert(int key, const char* buffer)
{
node* newptr = malloc(sizeof(node));
if (newptr == NULL)
{
return;
}
strcpy(newptr->name, buffer);
newptr->next = NULL;
if (first[key] == NULL)
{
first[key] = newptr;
}
else
{
node* predptr = first[key];
while (true)
{
if (predptr->next == NULL)
{
predptr->next = newptr;
break;
}
predptr = predptr->next;
}
}
}
In function insert() you correctly allocate the new node:
node* newptr = malloc(sizeof(node));
In this way you make room for a full struct node: a pointer to node and a pointer to char. But you don't allocate the space where those pointer are supposed to point.
So, when you copy the input buffer within name field, you are performing an illegal attempt to write to a char * pointer that has not been allocated and not even initialized:
strcpy(newptr->name, buffer);
All pointers need to be allocated (or at least initialized to a valid memory location) before writing in them. In your case:
newptr->name = malloc( strlen( buffer ) + 1 );
if( newptr->name )
{
strcpy(newptr->name, buffer);
}

Link Lists and Freeing Memory in C

I was trying to make a simple Link List struct but for some reason when I tested freeing up the data in the LL it would give me an invalid pointer error. Can anyone explain why?
#include <stdio.h>
#include <stdlib.h>
void add();
typedef struct node{
char* data;
struct node* next;
} node;
node** n;
int main(int argv, char** argc){
n = (node**)malloc(sizeof(node*)*10);
int i;
for(i = 0; i < 10; i++){
n[i] = NULL;
}
add();
free(n[0]->data);
return 0;
}
void add(){
char* temp = (char*)malloc(sizeof(char)*4);
temp = "Meh\0";
n[0] = (node*)malloc(sizeof(node));
n[0]->data = temp;
}
char* temp = (char*)malloc(sizeof(char)*4);
temp = "Meh\0";
Your assignment to temp is the culprit, as that sets it to point to the static character string "Meh\0", which it not yours to free. Your malloc has no effect in this case, as you immediately replace it to point to static data instead. Use memcpy or similar if you want to copy the data into the memory allocated by malloc.

How to make changes in an array through a function

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define SIZE 10
// A hashtable is a mixture of a linked list and array
typedef struct node NODE;
struct node{
int value;
NODE* next;
};
int hash(int);
void insert(int,NODE **);
int main(){
NODE* hashtable[SIZE];
insert(12,&hashtable[SIZE]);
printf("%d\n",hashtable[5]->value);
}
int hash(int data){
return data%7;
}
void insert(int value,NODE **table){
int loc = hash(value);
NODE* temp = malloc(sizeof(NODE));
temp->next = NULL;
temp->value = value;
*table[loc] = *temp;
printf("%d\n",table[loc]->value);
}
The above code prints :
12 and
27475674 (A random number probably the location.)
how do I get it to print 12 and 12 i.e. how to make a change in the array. I want to fill array[5] with the location of a node created to store a value.
The expression *table[loc] is equal to *(table[loc]) which might not be what you want, since then you will dereference an uninitialized pointer.
Then the assignment copies the contents of *temp into some seemingly random memory.
You then discard the memory you just allocated leading to a memory leak.
There's also no attempt to make a linked list of the hash-bucket.
Try instead to initially create the hashtable array in the main function with initialization to make all pointers to NULL:
NODE* hashtable[SIZE] = { NULL }; // Will initialize all elements to NULL
Then when inserting the node, actually link it into the bucket-list:
temp->next = table[loc];
table[loc] = temp;
This is just a simple change which I have made to your program which will tell you what you are actually doing wrong.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define SIZE 10
// A hashtable is a mixture of a linked list and array
typedef struct node NODE;
struct node {
int value;
NODE* next;
};
NODE *hashtable[SIZE] = { NULL };
int hash(int);
int insert(int); //, NODE **);
int main(void)
{
int loc = insert(12); //, &hashtable[SIZE]);
if (loc < SIZE) {
if (hashtable[loc]) {
printf("%d\n", hashtable[loc]->value);
} else {
printf("err: invalid pointer received\n");
}
}
return 0;
}
int hash(int data)
{
return data%7;
}
int insert(int value) //, NODE *table[])
{
int loc = hash(value);
printf("loc = %d\n", loc);
if (loc < SIZE) {
NODE *temp = (NODE *) malloc(sizeof(NODE));
temp->value = value;
temp->next = NULL;
hashtable[loc] = temp;
printf("%d\n", hashtable[loc]->value);
}
return loc;
}
Here I have declared the hashtable globally just to make sure that, the value which you are trying to update is visible to both the functions. And that's the problem in your code. Whatever new address you are allocating for temp is having address 'x', however you are trying to access invalid address from your main function. I just wanted to give you hint. Hope this helps you. Enjoy!

Dynamic array of linked lists in C

Basically I have to store words in linked list with each character having its own node. I get really confused with nested structures. How do I go to the next node? I know i'm doing this completely wrong which is why I'm asking.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct node
{
char letter;
}NODE;
typedef struct handle
{
NODE **arr;
}HANDLE;
HANDLE * create();
void insert(handle **, char, int);
int main(int argc, char **argv)
{
FILE *myFile;
HANDLE *table = (HANDLE *)malloc(sizeof(HANDLE));
NODE *linked = (NODE *)malloc(sizeof(NODE));
int counter = 0;
linked = NULL;
table->arr[0] = linked;
char c;
myFile = fopen(argv[argc], "r");
while((c = fgetc(myFile)) != EOF)
{
if(c != '\n')
insert(&table, c, counter);
else
{
counter++;
continue;
}
}
}
void insert(HANDLE **table, char c, int x)
{
(*table)->arr[x]->letter = c; //confused on what to do after this or if this
//is even correct...
}
You have a linked list of words with each word being a linked list of characters. Am I right? If so, it is better to use the names for what they are:
typedef struct char_list
{
char letter;
struct char_list * next;
} word_t;
typedef struct word_list
{
word_t * word;
struct word_list_t * next;
} word_list_t;
Now, you can populate the lists as per need.
For a linked-list, you typically have a link to the next node in the node structure itself.
typedef struct node
{
char letter;
struct node *next;
}NODE;
Then from any given node NODE *n, the next node is n->next (if not NULL).
insert should scan the list until it finds an n->next that is NULL, and allocate a new node at the end (make sure to set its next to NULL).
You may want to have a function to initialize a new list given the table index, and a separate function to initialize a new node.

Pointer trouble creating binary trees

I am creating a binary tree from a bitstring in c. ie 1100100 creates a tree:
1
/ \
1 1
I decided to use a recursive function to build this tree however i keep getting the error
Debug assertion failed...
Expression : CrtIsValidHeapPointer(pUserData)
here is a fragment of my code
typedef
struct Node {
char key;
struct Node *left;
struct Node *right;
} Node;
char string[1000];
int i = 0;
void insertRecursivePreorder(Node **node)
{
Node* parent = *node;
if(string[i] == '0')
{
parent = NULL;
i++;
}
else
{
Node *newn = (Node*)malloc(sizeof(Node));
newn->key = string[i];
parent = newn;
i++;
insertRecursivePreorder(&newn->left); //errors occur here
insertRecursivePreorder(&newn->right); //errors occur here
free(newn);
free(parent);
}
}
int main(void)
{
void printTree(Node* node);
Node* root = NULL;
scanf("%s", string);
insertRecursivePreorder(&root);
//... do other junk
}
i was wondering why this error comes about and what i can do to fix it.
The immediate problem is likely to be calling free on a pointer twice. In insertRecursivePreorder, you set parent to newn, and then call free on both. As an example of this, the following program fails (but works if you comment out one of the free(..)s):
#include <stdlib.h>
int main() {
int *a = malloc(sizeof(int)),
*b = a;
free(a);
free(b);
return 0;
}
However, there are several problems with your logic here. You should only call free when you have completely finished with the pointer, so if you are using your tree later you can't free it as you construct it. You should create a second function, recursiveDestroyTree, that goes through and calls free on the tree (from the bottom up!).
And, you probably want *node = newn rather than parent = newn, since the latter is the only one that actually modifies node.
(You could also change your function to return a Node * pointer, and then just go:
root = insertRecursivePreorder();
and
newn->left = insertRecursivePreorder();
newn->right = insertRecursivePreorder();
instead of trying to keep track of pointers to pointers etc.)
(Furthermore, on a stylistic point, using global variables is often bad practice, so you could have your insertRecursivePreorder take int i and char * string parameters and use them instead of global variables.)
The problem was: you were never assigning to the double pointer in 'insertRecursivePreorder', so root always stayed NULL.
#include <stdio.h>
#include <stdlib.h>
typedef
struct Node {
char key;
struct Node *left;
struct Node *right;
} Node;
/* slightly changed the syntax for the str
** ; now '.' indicates a NULL pointer, values represent themselves.
*/
char *string = "12..3.." ;
/* Removed the global index 'i' */
void printTree(Node* node, int level);
unsigned insertRecursivePreorder(Node **pp, char *str);
unsigned insertRecursivePreorder(Node **pp, char *str)
{
unsigned pos =1;
if (!*str) { *pp = NULL; return 0; } /* safeguard for end of string */
if (*str == '.') { *pp = NULL; return pos; }
*pp = malloc(sizeof **pp);
(*pp)->key = *str;
pos += insertRecursivePreorder(&(*pp)->left, str+pos);
pos += insertRecursivePreorder(&(*pp)->right, str+pos);
return pos;
}
void printTree(Node* node, int level)
{
unsigned pos,len;
len = level> 0 ? level : -level;
for (pos =0; pos < len; pos++) putchar (' ');
if (!level) printf ("Root=");
else if (level<0) printf ("Left=");
else printf ("Right=");
if (!node) { printf( "Null\n" ); return; }
printf("Key=%c\n", node->key );
printTree(node->left, -(len+1) ) ;
printTree(node->right, len+1) ;
}
int main(void)
{
Node *root = NULL;
unsigned result = 0;
result = insertRecursivePreorder(&root, string);
printf( "Result=%u\n", result);
printTree(root, 0);
return 0; printTree(root, 0);
}
Output:
Result=7
Root=Key=1
Left=Key=2
Left=Null
Right=Null
Right=Key=3
Left=Null
Right=Null

Resources