Im trying to create a simple hashmap in C. The vs doesnt know any errors at compilation time. But during execution, the pointer to the structure is becoming a bad pointer.
hashedKey CXX0030: Error: expression cannot be evaluated
Here is the code for that, can anyone tell me why the code is crashing.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<iostream>
using namespace std;
//#include"Header.h"
struct hashItem{
char* hashedKey;
char* hashedValue;
hashItem* next;
};
#define SIZE 20
unsigned long hashf(char *str)
{
unsigned long hash = 5381;
int c;
while (c = *str++)
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
return hash%SIZE;
}
struct hashItem * createNewItem(char *key, char *value){
struct hashItem *newKeyValue = (struct hashItem *)calloc(1, sizeof(struct
hashItem));
newKeyValue->hashedKey = (char*)malloc(sizeof(char) * 100);
newKeyValue->hashedValue = (char*)malloc(sizeof(char) * 100);
strcpy(newKeyValue->hashedKey, key);
newKeyValue->hashedValue = value;
newKeyValue->next = NULL;
return newKeyValue;
}
void put(struct hashItem** hashTable, char *key, char *value)
{
if (value == NULL)
return;
struct hashItem *newKeyValue = createNewItem(key, value);
int index = hashf(key);
if (hashTable[index] == NULL){
hashTable[index] = newKeyValue;
}
else
{
int inserted = 0;
struct hashItem *p = hashTable[index];
struct hashItem *q = NULL;
while (p != NULL){
int e = strcmp(p->hashedKey, newKeyValue->hashedKey);
if (e == 0){
if (q != NULL)
q->next = newKeyValue;
p->hashedValue = newKeyValue->hashedValue;
inserted = 1;
break;
}
q = p;
p = p->next;
}
if (!inserted)
q->next = newKeyValue;
}
}
struct hashItem * get(struct hashItem** hashTable, char *key){
if (hashTable == NULL)
return NULL;
int index = hashf(key);
if (hashTable[index] != NULL)
{
if (!strcmp(hashTable[index]->hashedKey, key)){
return hashTable[index];
}
else{
struct hashItem *p = hashTable[index];
while (p != NULL){
if (p->hashedKey == key)
return p;
p = p->next;
}
return NULL;
}
}
else{
return NULL;
}
}
int main(){
hashItem** hashtable = (hashItem**)malloc(sizeof(hashItem*)*20);
for (int i = 0; i < 20; i++){
hashtable[i] = (hashItem*)malloc(sizeof(hashItem));
hashtable[i]->hashedKey = NULL;
hashtable[i]->hashedValue = NULL;
hashtable[i]->next = NULL;
}
put(hashtable, "select", "marks");
hashItem* temp = (hashItem*)get(hashtable,"select");
printf("%s", temp->hashedKey);
int k;
scanf("%d", &k);
return 0;
}
During the debugging it seems the code is crashing at the exact line of:
struct hashItem *p = hashTable[index];
Please tell me why the code is crashing.
Basically you are thinking wrong about initializing the hash buckets.
In the main() function basically you only need to allocate memory for the buckets of the hash table, so you only need this:
hashItem** hashtable = (hashItem**)calloc(20, sizeof(hashItem**));
Pay attention that I am using calloc instead of malloc to make sure that it is going to initialize to NULL these memory region. So, basically here we created 20 buckets to be managed by the hash table.
Again, you should not do that for (int i = 0; i < 20; i++), that is wrong. You will manage the buckets at insertion time, so, when you are inserting something that is not in the hash table, then you allocate memory to that entry.
You are using a mixture of C and C++ here, please make sure to state that when you submit your question.
I will paste here the changes I made, because you were using a lot of casting to get the right pointer type, but it is not necessary if you usce the right structure types.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct _hashItem{
char* hashedKey;
char* hashedValue;
struct _hashItem* next;
} hashItem;
#define SIZE 20
unsigned long hashf(char *str)
{
unsigned long hash = 5381;
int c;
while (c = *str++)
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
return (hash % SIZE);
}
hashItem * createNewItem(char *key, char *value){
hashItem *newKeyValue = (hashItem *)calloc(1, sizeof(
hashItem));
newKeyValue->hashedKey = (char*)malloc(sizeof(char) * 100);
newKeyValue->hashedValue = (char*)malloc(sizeof(char) * 100);
strcpy(newKeyValue->hashedKey, key);
newKeyValue->hashedValue = value;
newKeyValue->next = NULL;
return newKeyValue;
}
void put(hashItem** hashTable, char *key, char *value)
{
if (value == NULL)
return;
hashItem *newKeyValue = createNewItem(key, value);
int index = hashf(key);
if (hashTable[index] == NULL){
hashTable[index] = newKeyValue;
}
else
{
int inserted = 0;
hashItem *p = hashTable[index];
hashItem *q = NULL;
while (p != NULL){
int e = strcmp(p->hashedKey, newKeyValue->hashedKey);
if (e == 0){
if (q != NULL)
q->next = newKeyValue;
p->hashedValue = newKeyValue->hashedValue;
inserted = 1;
break;
}
q = p;
p = p->next;
}
if (!inserted)
q->next = newKeyValue;
}
}
hashItem * get(hashItem** hashTable, char *kAey){
if (hashTable == NULL)
return NULL;
int index = hashf(key);
if (hashTable[index] != NULL)
{
if (!strcmp(hashTable[index]->hashedKey, key)){
return hashTable[index];
}
else{
hashItem *p = hashTable[index];
while (p != NULL){
if (p->hashedKey == key)
return p;
p = p->next;
}
return NULL;
}
}
else{
return NULL;
}
}
int main(){
hashItem** hashtable = (hashItem**)calloc(20, sizeof(hashItem**));
put(hashtable, "select", "marks");
hashItem* temp = get(hashtable,"select");
printf("%s", temp->hashedKey);
int k;
scanf("%d", &k);
return 0;
}
Related
I've a problem with memory allocation for an hash table with linked list (for avoid collisions) in C.
I think that the problem is on allocation of an item.
I've made two scruct, one for the single item and one for the table.
The first have two pointer to next and prev item.
Please help me.
I stay on this code until 3 days.
The code :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CAPACITY 50000
unsigned long hash(char *str) {
unsigned long int stringsum = 0;
for(; *str != '\0'; str++) {
stringsum += *str;
}
return stringsum % CAPACITY;
}
typedef struct item {
char *value;
char *key;
struct item *next;
struct item *prev;
} ht_item;
typedef struct hashtable {
ht_item **items;
int dim;
int count;
} HashTable;
HashTable* create_table(int size); HashTable* create_item(HashTable *table, char *value, char *key);
void print_table(HashTable* table, int dim);
int main(void) {
HashTable *table = create_table(CAPACITY);
table = create_item(table, "Giuseppe", "Nome");
print_table(table, CAPACITY);
return 0;
}
HashTable* create_item(HashTable *table, char *value, char *key) {
unsigned long index = hash(key);
printf("%u", index);
ht_item *_iterator; ht_item *prev;
for(_iterator = table->items[index], prev = NULL; _iterator != NULL; prev = _iterator, _iterator = _iterator->next);
_iterator = (ht_item*)malloc(sizeof(ht_item));
_iterator->key = (char*)malloc(200);
_iterator->value = (char*)malloc(200);
strcpy(_iterator->key, key);
strcpy(_iterator->value, value);
_iterator->next = NULL;
_iterator->prev = prev;
return table;
}
HashTable* create_table(int size)
{
HashTable *table = (HashTable*)malloc(sizeof(HashTable));
table->dim = size;
table->items = (ht_item**)calloc(size, sizeof(ht_item*));
for(int i = 0; i < size; i++){
table->items[i] = NULL;
}
return table;
}
void print_table(HashTable* table, int dim) {
for(int i = 0; i < CAPACITY; i++)
{
if(table->items[i] != NULL)
{ ht_item *_iterator = (ht_item*)malloc(sizeof(ht_item));
for(_iterator = table->items[i]; _iterator != NULL;
_iterator = _iterator->next)
{
printf("Key: %s\tValue: %s\n", _iterator->key, _iterator->value);
} free(_iterator);
}
}
}
Made some changes in your code. Please read through the blocks containing // CHANGE HERE comment.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CAPACITY 50000
// CHANGE HERE - additional parameter, value to be used for modulo
unsigned long hash(char *str, unsigned int mod_value) {
unsigned long int stringsum = 0;
for(; *str != '\0'; str++) {
stringsum += *str;
}
// CHANGE HERE - use mod_value instead of CAPACITY
return stringsum % mod_value;
}
typedef struct item {
char *value;
char *key;
struct item *next;
struct item *prev;
} ht_item;
typedef struct hashtable {
ht_item **items;
int dim;
int count;
} HashTable;
HashTable* create_table(int size); HashTable* create_item(HashTable *table, char *value, char *key);
void print_table(HashTable* table, int dim);
int main(void) {
HashTable *table = create_table(CAPACITY);
table = create_item(table, "Giuseppe", "Nome");
print_table(table);
return 0;
}
HashTable* create_item(HashTable *table, char *value, char *key) {
// CHANGE HERE - function arguments validation
if (table == NULL)
{
return table;
}
if (value == NULL || key == NULL)
{
printf("Key or value is null\n");
return table;
}
// CHANGE HERE - pass table->dim to hash
unsigned long index = hash(key, table->dim);
printf("Index: %lu\n", index);
// CHANGE HERE - simplified the code a bit
ht_item* new_node = malloc(sizeof(ht_item));
new_node->key = malloc(200 * sizeof(char));
strncpy(new_node->key, key, 200);
new_node->value = malloc(200 * sizeof(char));
strncpy(new_node->value, value, 200);
// CHANGE HERE - if first node in index
if (table->items[index] == NULL)
{
table->items[index] = new_node;
return table;
}
ht_item *cur, *prev = NULL;
for(cur = table->items[index]; cur != NULL; prev = cur, cur = cur->next);
prev->next = new_node; // CHANGE HERE - it seems this line was missing
new_node->prev = prev;
new_node->next = NULL;
return table;
}
HashTable* create_table(int size)
{
HashTable *table = (HashTable*)malloc(sizeof(HashTable));
table->dim = size;
table->items = (ht_item**)calloc(size, sizeof(ht_item*));
for(int i = 0; i < size; i++){
table->items[i] = NULL;
}
return table;
}
void print_table(HashTable* table) {
// CHANGE HERE - function arguments validation
if (table == NULL)
{
printf("Table is null\n");
return;
}
// CHANGE HERE - change CAPACITY to dim
for(int i = 0; i < table->dim; i++)
{
//printf("i = %d [%d]\n", i, table->items[i] == NULL);
if(table->items[i] != NULL)
{
// CHANGE HERE - removed unnecessary malloc
ht_item *_iterator = NULL;
for(_iterator = table->items[i]; _iterator != NULL; _iterator = _iterator->next)
{
printf("Key: %s\tValue: %s\n", _iterator->key, _iterator->value);
}
}
}
}
The create_item function can and should be simplified.
I have put some comments inline.
HashTable* create_item(HashTable *table, char *value, char *key) {
// use modulo operator here, not in the hash function
unsigned long index = hash(key) % table->dim;
// nicer way of allocating
ht_item *insert = malloc(sizeof *insert);
// use strdup to avoid wasted memory and buffer overflows
insert->key = strdup(key);
insert->value = strdup(value);
// head insert rather than tail
insert->next = table->items[index];
table->items[index] = insert;
return table;
}
I dropped the use of the prev member. If you need that somewhere it's an exercise for you to add it. I don't think it's necessary for a simple hash table.
I am trying to add memory deallocations to old C code.
I have a hash table of custom objects (HASHREC). After analysis of current code and reading other SO questions, I know that I need to provide three levels of deallocations. Fist - word member, next HASHREC*, and then HASHREC**.
My version of free_table() function frees mentioned objects. Unfortunately, Valgrind still complains that some bytes are lost.
I am not able to provide full code, it will be too long, but I am presenting how HASHREC **vocab_hash is filled inside inithashtable() and hashinsert().
Could you give me a suggestion how should I fix free_table()?
typedef struct hashrec {
char *word;
long long count;
struct hashrec *next;
} HASHREC;
HASHREC ** inithashtable() {
int i;
HASHREC **ht;
ht = (HASHREC **) malloc( sizeof(HASHREC *) * TSIZE );
for (i = 0; i < TSIZE; i++) ht[i] = (HASHREC *) NULL;
return ht;
}
void hashinsert(HASHREC **ht, char *w) {
HASHREC *htmp, *hprv;
unsigned int hval = HASHFN(w, TSIZE, SEED);
for (hprv = NULL, htmp = ht[hval]; htmp != NULL && scmp(htmp->word, w) != 0; hprv = htmp, htmp = htmp->next);
if (htmp == NULL) {
htmp = (HASHREC *) malloc( sizeof(HASHREC) ); //<-------- problematic allocation (Valgrind note)
htmp->word = (char *) malloc( strlen(w) + 1 );
strcpy(htmp->word, w);
htmp->next = NULL;
if ( hprv==NULL ) ht[hval] = htmp;
else hprv->next = htmp;
}
else {/* new records are not moved to front */
htmp->count++;
if (hprv != NULL) { /* move to front on access */
hprv->next = htmp->next;
htmp->next = ht[hval];
ht[hval] = htmp;
}
}
return;
}
void free_table(HASHREC **ht) {
int i;
HASHREC* current;
HASHREC* tmp;
for (i = 0; i < TSIZE; i++){
current = ht[i];
while(current != NULL) {
tmp = current;
current = current->next;
free(tmp->word);
}
free(ht[i]);
}
free(ht);
}
int main(int argc, char **argv) {
HASHREC **vocab_hash = inithashtable();
// ...
hashinsert(vocab_hash, w);
//....
free_table(vocab_hash);
return 0;
}
I assume the problem is here:
current = ht[i];
while(current != NULL) {
tmp = current;
current = current->next;
free(tmp->word);
}
free(ht[i]);
You release the word but you don’t release tmp. After you release the first item in the linked list but not the others which causes a leak.
Free tmp in there and don’t free ht[i] after since it’s already freed here.
current = ht[i];
while(current != NULL) {
tmp = current;
current = current->next;
free(tmp->word);
free(tmp);
}
I am working on a project in C and it is working great except for one function which seems to be overwriting my array and writing weird numbers such as 1970802352 which keeps count of word occurrences in a file
this is my header file:
#ifndef LIST_H
#define LIST_H
struct Node_{
char* word;
//array holding names of files word occurs in
char **filesIn;
int numFilesIn;
//array holding count of how many times word occured in file
int* occursIn;
struct Node_ *next;
int isHead;
};
typedef struct Node_ Node;
int insert(char *wordToAdd, char *File);
int addOccur(Node *addedTo, char *File);
Node *createNode(char *wordToAdd, char *File);
void destroyNodes();
#endif
and this is the function that keeps overwriting the array:
Node *head;
int insert(char *wordToAdd, char *File){
if(head == NULL){
Node *new;
new = createNode(wordToAdd, File);
new->isHead = 1;
head = new;
return 0;
}
else{
Node *trace;
trace = head;
char *traceWord;
int wordSize;
wordSize = strlen(trace->word);
traceWord = (char*) malloc(wordSize + 1);
strcpy(traceWord, trace->word);
int a =strcmp(wordToAdd, traceWord);
free(traceWord);
if(a == 0){
int b = addOccur(trace, File);
//printf("addOccur returned %d\n", b);
return 0;
}
if(a < 0){
Node *Insert = createNode(wordToAdd, File);
trace->isHead = 0;
Insert->isHead = 1;
Insert->next = trace;
head = Insert;
return 0;
}
else{
Node *backTrace;
backTrace = head;
while(trace->next != NULL){
trace = trace->next;
traceWord = trace->word;
a = strcmp(wordToAdd, traceWord);
if(a < 0){
Node* Insert = createNode(wordToAdd, File);
Insert->next = trace;
backTrace->next = Insert;
return 0;
}
if(a == 0){
addOccur(trace, File);
//free(wordToAdd);
return 0;
}
if(a > 0){
backTrace = trace;
continue;
}
}
Node *Insert = createNode(wordToAdd, File);
trace->next = Insert;
return 0;
}
}
return 1;
}
and the other functions are:
Node* createNode(char *wordToAdd, char *File){
Node *new;
new = (Node*)malloc(sizeof(Node));
memset(new, 0, sizeof(Node));
new->word = wordToAdd;
char **newArray;
newArray = (char**)malloc(sizeof(char*));
newArray[0] = File;
new->filesIn = newArray;
int a[1];
a[0] = 1;
new->occursIn = a;
//new->occursIn[0] = 1;
new->numFilesIn = 1;
return new;
}
int addOccur(Node *addedTo, char *File){
char **fileList = addedTo->filesIn;
char *fileCheck;
int i = 0;
int fileNums = addedTo->numFilesIn;
for(i = 0; i < fileNums; i++){
fileCheck = fileList[i];
if(strcmp(fileCheck, File) == 0){
int *add1;
add1 = addedTo->occursIn;
int j = add1[i];
j++;
add1[i] = j;
return 0;
}
}
int numberOfFilesIn;
numberOfFilesIn = addedTo->numFilesIn;
char **newList = (char**)malloc(sizeof(char*) * numberOfFilesIn + sizeof(char*));
i = 0;
char *dest;
char *src;
for(i = 0; i < numberOfFilesIn; i++){
src = fileList[i];
int len;
len = strlen(src);
dest = (char*)malloc(sizeof(char) * (len + 1));
strcpy(dest, src);
newList[i] = dest;
}
int len2;
len2 = strlen(File);
newList[i] = File;
free(fileList);
int r = addedTo->numFilesIn;
r++;
addedTo->numFilesIn = r;
addedTo->filesIn = newList;
i = 0;
int *g;
g = addedTo->occursIn;
int count2;
count2 = addedTo->numFilesIn;
count2++;
int a[count2];
for(i = 0; i < count2 -1; i++){
a[i] = g[i];
}
a[count2 - 1] = 1;
return 0;
}
When going to gdb i notice that the value of
head->occursIn[0]
changes after the line
wordSize = strlen(trace->word);
and I have no clue why.
In your CreateNode() function, you are not allocating storage for the occursIn array. You are simply declaring a local array within the function and then assigning the occursIn pointer:
int a[1];
a[0] = 1;
new->occursIn = a;
The array a[1] goes away when the createNode function returns, so at that point your occursIn pointer is pointing to a value that is subject to being overwritten.
And even if the storage was allocated correctly in createNode, you've set a fixed size for the array but your whole strategy depends on that array having an element for each file; and in addOccurs you don't do anything to allocate a new larger array for a new file.
You may want to re-evaluate your strategy and switch to using lists instead of arrays.
I have been working on this little project for quite some time and I can't figure out why I'm not getting the results that are expected. I am a beginner to C programming so my understanding with pointers and memory allocation/deallocation is novice. Anyways, I have constructed this segment of code by originally building a hash function, then adding a count to it. However, when I test it, sometimes the count works, sometimes it doesn't. I'm not sure whether it's the fault of the hash function, or the fault of the way I set up my count. The text file is read one line at a time and is a string consisting of a hexadecimal.
struct node {
char *data;
struct node *next;
int count; /* Implement count here for word frequencies */
};
#define H_SIZE 1024
struct node *hashtable[H_SIZE]; /* Declaration of hash table */
void h_lookup(void)
{
int i = 0;
struct node *tmp;
for(i = 0; i < H_SIZE; i++) {
for(tmp = hashtable[i]; tmp != NULL; tmp = tmp->next) {
if(tmp->data != 0) {
printf("Index: %d\nData: %s\nCount: %d\n\n", i,
tmp->data, tmp->count);
}
}
}
}
/* self explanatory */
void h_add(char *data)
{
unsigned int i = h_assign(data);
struct node *tmp;
char *strdup(const char *s);
/* Checks to see if data exists, consider inserting COUNT here */
for(tmp = hashtable[i]; tmp != NULL; tmp = tmp->next) {
if(tmp->data != 0) { /* root node */
int count = tmp->count;
if(!strcmp(data, tmp->data))
count= count+1;
tmp->count = count;
return;
}
}
for(tmp = hashtable[i]; tmp->next != NULL; tmp = tmp->next);
if(tmp->next == NULL) {
tmp->next = h_alloc();
tmp = tmp->next;
tmp->data = strdup(data);
tmp->next = NULL;
tmp->count = 1;
} else
exit(EXIT_FAILURE);
}
/* Hash function, takes value (string) and converts into an index into the array of linked lists) */
unsigned int h_assign(char *string)
{
unsigned int num = 0;
while(*string++ != '\0')
num += *string;
return num % H_SIZE;
}
/* h_initialize(void) initializes the array of linked lists. Allocates one node for each list by calling h_alloc which creates a new node and sets node.next to null */
void h_initialize(void)
{ int i;
for(i = 0; i <H_SIZE; i++) {
hashtable[i] = h_alloc();
}
}
/* h_alloc(void) is a method which creates a new node and sets it's pointer to null */
struct node *h_alloc(void)
{
struct node *tmp = calloc(1, sizeof(struct node));
if (tmp != NULL){
tmp->next = NULL;
return tmp;
}
else{
exit(EXIT_FAILURE);
}
}
/* Clean up hashtable and free up memory */
void h_free(void)
{
struct node *tmp;
struct node *fwd;
int x;
for(x = 0; x < H_SIZE; x++) {
tmp = hashtable[x];
while(tmp != NULL) {
fwd = tmp->next;
free(tmp->data);
free(tmp);
tmp = fwd;
}
}
}
I assume that the count is not being incremented when it does not work. It is possible that strdup is not able to allocate memory for the new string and is returning NULL. You should check the return value to and exit gracefully if it fails.
So all I'm trying to do is free a pointer and it just gives me the error 'invalid address'; though the address is clearly valid, as illustrated by the prints I put in. It tries to free the address of the pointer, but still fails. Through valgrind, it gives the error invalid free() saying the address is on thread 1's stack? The code below is runnable; can anyone help?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#define SUCC 1
#define FAIL -1
typedef struct bucket {
char *key;
void *value;
struct bucket *next;
} Bucket;
typedef struct {
int key_count;
int table_size;
void (*free_value)(void *);
Bucket **buckets;
} Table;
extern unsigned int hash_code(const char *key) {
unsigned int hash = 0, i = 0;
while(i < strlen(key)) {
hash ^= ((hash << 3) | (hash >> 29)) + key[i++];
}
return hash;
}
/*Makes copy of string and returns pointer to it*/
char * cpy(const char *str) {
char *new = malloc(sizeof(char *));
if(new)
strcpy(new, str);
return new;
}
int create_table(Table ** table, int table_size, void (*free_value)(void *)) {
*table = malloc(sizeof(Table));
if(table && table_size != 0) {
int i = 0;
(*table)->key_count = 0;
(*table)->table_size = table_size;
(*table)->free_value = free_value;
(*table)->buckets = calloc(table_size, sizeof(Bucket *));
while(i < table_size)
(*table)->buckets[i++] = NULL;
return SUCC;
}
return FAIL;
}
int put(Table * table, const char *key, void *value) {
if(table && key) {
int hash = hash_code(key)%table->table_size;
Bucket *curr = table->buckets[hash];
while(curr) {
if(strcmp(curr->key, key) == 0) {
if(table->free_value)
table->free_value(curr->value);
printf("addr of ptr: %p\n", value);
curr->value = value;
printf("addr of curr ptr: %p\n", curr->value);
return SUCC;
}
curr = curr->next;
}
curr = malloc(sizeof(Bucket));
curr->key = cpy(key);
printf("addr of ptr: %p\n", value);
curr->value = value;
printf("addr of curr ptr: %p\n", curr->value);
curr->next = table->buckets[hash];
table->buckets[hash] = curr;
table->key_count++;
return SUCC;
}
return FAIL;
}
int remove_entry(Table * table, const char *key) {
if(table && key) {
int hash = hash_code(key)%(table->table_size);
Bucket *curr = table->buckets[hash], *prev = table->buckets[hash];
while(curr) {
printf("attempt");
if(strcmp(curr->key, key) == 0) {
void * test = curr->value;
printf("at addr %p\n", test);
table->free_value(test);
printf("freed");
if(table->free_value){
table->free_value(curr->value);
}
free(curr->key);
curr->key = NULL;
curr->value = NULL;
table->key_count--;
if(prev == curr)
table->buckets[hash] = curr->next;
else
prev->next = curr->next;
free(curr);
curr = NULL;
return SUCC;
}
prev = curr;
curr = curr->next;
}
}
return FAIL;
}
And the test file that shows the error:
#include <stdio.h>
#include <stdlib.h>
#include "htable.h"
int main() {
Table *t;
int num2 = 3;
printf("create: %d\n",create_table(&t, 2, free));
printf("addr of ptr: %p\n",(void *)&num2);
printf("put %s: %d\n","test",put(t, "test", &num2));
printf("rem key: %d\n",remove_entry(t, "test"));
return 0;
}
This is broken:
char *new = malloc(sizeof(char *));
The amount of memory you need is based on what you need to store, which is the string. You want:
char *new = malloc(strlen(str) + 1);
Or, better yet, just use strdup.
You are trying to free() a stack variable: num2 (in main()):
int num2 = 3;
Later, you have this call:
printf("put %s: %d\n","test",put(t, "test", &num2));
You're passing the address of num2 to put(), which means that remove_entry() will try to free it later. This is illegal. You cannot free a variable allocated on the stack. You should dynamically allocate num2 instead:
int* num2 = malloc(sizeof(int));
*num2 = 3;
There's another problem as well though. In this code:
void * test = curr->value;
printf("at addr %p\n", test);
table->free_value(test);
printf("freed");
if(table->free_value){
table->free_value(curr->value);
}
You are freeing curr->value twice, because you're freeing test which is just a copy of the pointer.