I am currently developing a memory allocator, I have come with this code a the moment but this code below segfault on almost every commands when i do a LD_PRELOAD of my implementation.
#include <pthread.h>
#include "malloc.h"
t_mem_map g_map;
int g_empty_map = TRUE;
static t_ctrl *get_free_block(size_t size)
{
t_ctrl *tmp;
tmp = g_map.head;
while (tmp != NULL)
{
if (tmp->is_free == TRUE && tmp->size < size)
{
tmp->is_free = FALSE;
return (tmp);
}
tmp = tmp->next;
}
return (NULL);
}
static void *init_map(size_t size)
{
t_ctrl *tmp;
g_map.map_size = DEFAULT_MAP_SIZE;
while (g_map.map_size < size + sizeof(t_ctrl))
g_map.map_size += DEFAULT_MAP_SIZE;
if ((g_map.head = (t_ctrl *)sbrk(g_map.map_size)) == (void *)-1)
return (NULL);
tmp = g_map.head;
tmp->next = NULL;
tmp->prev = NULL;
tmp->size = size;
tmp->is_free = FALSE;
g_map.free_space = g_map.map_size - size - sizeof(t_ctrl);
g_empty_map = FALSE;
unlock_thread();
return ((void *)((char *)tmp + sizeof(t_ctrl)));
}
static void *add_block(size_t size)
{
t_ctrl *tmp;
t_ctrl *new;
tmp = get_free_block(size);
if (tmp != NULL)
return ((void *)((char *)tmp + sizeof(t_ctrl)));
tmp = g_map.head;
while (tmp->next != NULL)
tmp = tmp->next;
new = (t_ctrl *)((char *)tmp + sizeof(t_ctrl) + tmp->size);
new->prev = tmp;
new->next = NULL;
tmp->next = new;
new->size = size;
new->is_free = FALSE;
g_map.free_space -= (new->size + sizeof(t_ctrl));
unlock_thread();
return ((void *)((char *)new + sizeof(t_ctrl)));
}
static void *resize_map(size_t size)
{
size_t size_shift;
size_shift = 0;
while (g_map.free_space < size + sizeof(t_ctrl))
{
g_map.map_size += DEFAULT_MAP_SIZE;
g_map.free_space += DEFAULT_MAP_SIZE;
size_shift += DEFAULT_MAP_SIZE;
}
if (sbrk(size_shift) == (void *)-1)
return (NULL);
return (add_block(size));
}
void *malloc(size_t size)
{
size_t a_size;
lock_thread();
a_size = ALIGN(size);
if (g_empty_map == TRUE)
return (init_map(a_size));
else
{
if ((a_size + sizeof(t_ctrl)) <= g_map.free_space)
return (add_block(a_size));
else
return (resize_map(a_size));
}
return (NULL);
}
Here is the malloc.h :
# include <stdio.h>
# include <stddef.h>
# include <unistd.h>
# define TRUE 0
# define FALSE 1
# define SUCCESS 0
# define FAILURE 1
# ifndef __X86_64__
# define ALIGNMENT (16)
# else
# define ALIGNMENT (8)
# endif
# define ALIGN(size) (((size) + (ALIGNMENT - 1)) &~ (ALIGNMENT - 1))
# define DEFAULT_MAP_SIZE (ALIGN(sysconf(_SC_PAGESIZE)))
typedef struct s_ctrl
{
size_t is_free;
size_t size;
struct s_ctrl *next;
struct s_ctrl *prev;
} t_ctrl;
typedef struct s_mem_map
{
size_t map_size;
size_t free_space;
// int free_blocks;
//int nb_blocks;
t_ctrl *head;
} t_mem_map;
With some research I found out that the segfault is likely coming from the while loop in the get_free_block() function but i can't understand why.
static t_ctrl *get_free_block(size_t size)
{
t_ctrl *tmp;
tmp = g_map.head;
while (tmp != NULL)
{
if (tmp->is_free == TRUE && tmp->size < size)
{
tmp->is_free = FALSE;
return (tmp);
}
tmp = tmp->next;
}
return (NULL);
}
Can't verify that this is the only problem, but you are checking tmp->size < size, when you probably should check tmp->size >= size instead.
Related
So, I'm currently going thorugh the book "Crafting Interpreters", one of the challenges is to allocate a big chunk of memory (only once) in the beginning of the program and manage it.
So far i've written this piece of code, but I'm not quite shure that I'm in the right direction.
#include <stdio.h>
#include "stdbool.h"
#include "stdlib.h"
typedef struct node {
_Bool free;
struct node* next;
} freeList;
#define IS_VALID(head) ((head)->next == NULL) ? 0 : 1
#define BLOCK_SIZE 8
void initFreeList(freeList* head, size_t size);
void* malloc_(freeList* head, size_t size);
void free_(freeList* head, void* var);
void initFreeList(freeList* head, size_t size)
{
freeList* ptr = NULL;
head->next = NULL;
head->free = true;
ptr = head;
for (int i = 0; i < size; i++) {
freeList* temp = malloc(sizeof(freeList*));
temp->next = NULL;
temp->free = true;
ptr->next = temp;
ptr = temp;
}
}
// Removes a node from the freeList and returns a void pointer.
void* malloc_(freeList* head, size_t size)
{
void* block = NULL;
freeList* ptr = NULL, *prev = NULL, *temp_ptr = NULL;
int counter = 0;
if (!IS_VALID(head))
return NULL;
while((size) % BLOCK_SIZE != 0)
size++;
for (ptr = head; ptr->next != NULL && ptr->free == true && counter < size;) {
counter += BLOCK_SIZE;
prev = ptr;
ptr = ptr->next;
ptr->free = false;
}
temp_ptr = ptr;
for (counter = 0; counter < size; counter += BLOCK_SIZE, temp_ptr = temp_ptr->next)
temp_ptr->free = false;
prev->next = temp_ptr->next;
temp_ptr->next = NULL;
block = ptr;
return block;
}
void free_(freeList* head, void* var)
{
_Bool flag = true;
while(head && flag) {
if (head->next == NULL) {
head->next = (freeList *) var;
head->next->free = true;
head->next->next = NULL;
flag = false;
}
head = head->next;
}
}
int main()
{
freeList* head = malloc(sizeof(freeList));
initFreeList(head, 10);
char* str = malloc_(head, 16);
int *var1 = malloc_(head, 8), *var2 = malloc_(head, 8);
sprintf(str, "%s", "Hello world !");
*var1 = 2000000000;
*var2 = 257;
free_(head, var1);
free_(head, str);
free_(head, var2);
printf("%s\n%d %d\n", str, *var1, *var2);
return 0;
}
I'm able to allocate memory for the variables in main, and when freeing the chunks are added back to the free list but some of them get lost, I guess it's because when I assigned memory using the
malloc_ im overwriting memory. What will be the right approach for this kind of problem ?
I made a hashtable, and it runs fine, but when i run it with valgrind,it tells me there is memory leaks when creating the hashtable and a memory leak for every user insertion, 12 bytes per insertion and 40 for creating the hashtable
here is some testable code:
#include <malloc.h>
#include <stdio.h>
#include "string.h"
#include "stdlib.h"
#define initial_size 5
typedef struct user_pos {
char nick[6];
int position_in_file;
}user_pos;
typedef struct bucket{
user_pos *info;
}bucket;
typedef struct hashtable{
int size;
int elements;
bucket **buckets;
}hashtable;
unsigned hash(char *s) {
unsigned hashval;
for (hashval = 0; *s != '\0'; s++)
hashval = *s + 31*hashval;
return hashval;
}
hashtable * create() {
hashtable *htable;
if((htable = malloc(sizeof(hashtable))) == NULL)
return NULL;
if((htable->buckets = malloc(sizeof(bucket) * initial_size)) == NULL)
return NULL;
htable->size = initial_size;
htable->elements = 0;
for(int i=0; i < initial_size; i++){
htable->buckets[i] = NULL;
}
return htable;
}
void insert(hashtable *hashtable, char *nick, int position_in_file){
int hash_value = hash(nick);
int new_position = hash_value % hashtable->size;
if (new_position < 0) new_position += hashtable->size;
int position = new_position;
while (hashtable->buckets[position] != NULL && position != new_position - 1) {
if(hashtable->buckets[position]->info != NULL){
position++;
position %= hashtable->size;
}else{
break;
}
}
hashtable->buckets[position] = malloc(sizeof(bucket));
hashtable->buckets[position]->info = malloc(sizeof(user_pos));
strcpy(hashtable->buckets[position]->info->nick, nick);
hashtable->buckets[position]->info->position_in_file = position_in_file;
hashtable->elements++;
}
void delete_hashtable(hashtable *ht) {
for(int i = 0; i<ht->size; i++){
if(ht->buckets[i] != NULL && ht->buckets[i]->info != NULL)
free(ht->buckets[i]);
}
free(ht);
}
int main(){
hashtable *ht = create();
insert(ht, "nick1", 1);
insert(ht, "nick2", 2);
delete_hashtable(ht);
return 0;
}
I am initializing a bucket everytime i insert a new item, but i think i cant free it after, because that would erase what was just added, the same for the create() function.
How do i avoid leaking memory in this case?
Thanks in advance.
The memory leak is not in your allocation function but in the cleanup. You fail to free everything you allocated in delete_hashtable.
You clean up ht->buckets[i] and ht, but fail to clean up ht->buckets[i]->info and ht->buckets. You need to free those as well:
void delete_hashtable(hashtable *ht) {
for(int i = 0; i<ht->size; i++){
if(ht->buckets[i] != NULL && ht->buckets[i]->info != NULL)
free(ht->buckets[i]->info);
free(ht->buckets[i]);
}
free(ht->buckets);
free(ht);
}
Also, you're allocating the wrong number of bytes for htable->buckets:
if((htable->buckets = malloc(sizeof(bucket) * initial_size)) == NULL)
Each element is a bucket *, not a bucket, so that's the size you should use:
if((htable->buckets = malloc(sizeof(bucket *) * initial_size)) == NULL)
Or better yet:
if((htable->buckets = malloc(sizeof(*htable->buckets) * initial_size)) == NULL)
That way it doesn't matter what the type of htable->buckets is or if you change it later.
I get a segmentation fault (core dumped) in the following peace of code (I'm implementing malloc(), free() and realloc()):
void free(void* ptr)
{
void* curr = head;
void* before = NULL;
int isLegal = 0;
/*Line X*/printf("curr is %p and ptr is %p\n", curr, ptr);
if(curr == ptr)
{
printf("aaa");
}
else
{
printf("bbb");
}
/*Some more code that actually frees the pointer and not relevant here*/
}
Now, you'd assume that it'd print aaa or bbb, it just announces a segmentation fault right after performing the printf() in line X. If I type "printf("a")" instead of the current printf() it won't print 'a' at all. That is really weird.
It prints:
curr is 0x86be000 and ptr is 0x86be000
and yet it would just exit and throw a segmentation fault right after.
The variable head is a static variable in that file. I really want to know where the problem is, it's really weird. Here's the statement from the header file:
void free(void* ptr);
As simple as that, do you see any problem in here?
The full code is available here but I doubt it's related, the program should, at least, print either 'aaa' or 'bbb', and it doesn't do that.
Any idea? I'm really desperate.
Following code complied with warnings but did execute perfectly
#include <unistd.h>
typedef struct metadata_block* p_block;
typedef struct metadata_block
{
size_t size;
p_block next;
int free;
}metadata_block;
void* malloc(size_t size);
void free(void* ptr);
void* realloc(void* ptr, size_t size);
//THE MAIN CODE IS AT THE BOTTOM//
#include <stdio.h>
static p_block head = NULL;
void* malloc(size_t size)
{
void* ptr;
int isOk = 1;
int temp = 0;
p_block curr = head;
if(size <= 0)
{
return NULL;
}
if(curr)
{
while(curr->next && isOk)
{
if(curr->free && size <= curr->size)
{
isOk = 0;
}
if(isOk)
{
curr = curr->next;
}
}
if(isOk) //what will happen if there isn't one free and big enough
{
ptr = sbrk(size + sizeof(metadata_block));
if((int)ptr <= 0)
return NULL;
((p_block)(ptr))->size = size;
((p_block)(ptr))->next = NULL; //next run it's the real next.
((p_block)(ptr))->free = 0;
return (ptr + sizeof(metadata_block));
}
else
{
if(curr->next)
{
ptr = curr;
if(curr->size == size || size > (curr->size - sizeof(metadata_block) - 1)) //not enough room for another block of memory
{
((p_block)(ptr))->free = 0;
return (ptr + sizeof(metadata_block));
}
temp = curr->size;
((p_block)(ptr))->size = size;
((p_block)(ptr))->free = 0;
((p_block)(ptr + sizeof(metadata_block) + size))->next = curr->next;
((p_block)(ptr))->next = ptr + sizeof(metadata_block) + size;
((p_block)(ptr + sizeof(metadata_block) + size))->size = temp - size;
((p_block)(ptr + sizeof(metadata_block) + size))->free = 1;
return (ptr + sizeof(metadata_block));
}
else
{
ptr = curr;
if((int)sbrk(size - curr->size) > 0)
{
((p_block)(ptr))->size = size;
((p_block)(ptr))->next = NULL; //next run it's the real next.
((p_block)(ptr))->free = 0;
return (ptr + sizeof(metadata_block));
}
return NULL;
}
}
}
else
{
ptr = sbrk(size + sizeof(metadata_block));
if((int)ptr <= 0)
return NULL;
head = ptr;
((p_block)(ptr))->size = size;
((p_block)(ptr))->next = NULL;
((p_block)(ptr))->free = 0;
}
return ptr;
}
void free(void* ptr)
{
void* curr = head;
void* before = NULL;
int isLegal = 0;
printf("curr is %p and ptr is %p\n", curr, ptr);
if(curr == ptr)
{
printf("aaa\n");
}
else
{
printf("bbb\n");
}
if(curr && ptr)
{
while(curr && !isLegal)
{
if(((p_block)(ptr)) == ((p_block)(curr))->next)
{
before = curr;
isLegal = 1;
curr = ((p_block)(curr))->next;
}
else
{
curr = ((p_block)(curr))->next;
}
}
if(isLegal)
{
curr = curr - sizeof(metadata_block);
if(((p_block)(curr))->next)
{
((p_block)(curr))->free = 1;
}
else
{
sbrk(0-(((p_block)(curr))->size + sizeof(metadata_block)));
((p_block)(before))->next = NULL;
}
}
}
}
void* realloc(void* ptr, size_t size)
{
void* ptr2 = malloc(size);
int i;
for(i = 0 ; i < size ; i++)
{
*((char*)(ptr2 + i)) = *((char*)(ptr + i));
}
free(ptr);
return ptr2;
}
int main()
{
printf("I'm in.\n");
char * str = malloc(10);
printf("After Malloc()\n");
void * ptr = (void *) str;
void * ptr2;
if(!str)
{
printf("Fail.\n");
}
strcpy(str,"TEST!\0");
printf("About to free\n");
free(str);
printf("free: OK!\n");
}
Output :
I'm in.
After Malloc()
About to free
curr is 0x1049000 and ptr is 0x1049000
aaafree: OK!
note - Instaed of your mm.h include I included codes in same file
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.
I'm looking for some help with some C dll programming. I am getting an error in Visual Studio that occurs when I call free from within the dll. The program runs fine in debug mode within the IDE, but when I try to execute it as "Start without debugging", the program crashes. I read that with debugging, the heap is shared, which probably explains why the code runs fine with F5 and not Ctrl-F5. Is this correct??
I've searched around, and I learned that it is dangerous to pass dynamically allocated memory through the dll-exe boundary, however as I am calling malloc and free from within the same dll, this should not be a problem. I have posted the code below. Any help would be greatly appreciated. Please note that this code works on my Linux box, I am simply trying to port it to Windows to garner experience programming in Windows.
Thank you
#ifndef HASHTABLE_H
#define HASHTABLE_H
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the HASHTABLE_EXPORTS
// symbol defined on the command line. This symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// HASHTABLE_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
#ifdef HASHTABLE_EXPORTS
#define HASHTABLE_API __declspec(dllexport)
#else
#define HASHTABLE_API __declspec(dllimport)
#endif
#ifdef __cplusplus
extern "C" {
#endif
/**
* This is a naive implementation
* of a hashtable
*/
typedef struct node {
struct node *next;
char *value;
char *key;
} Node;
typedef struct hashtable {
struct node **nodes;
int num_elements;
int size;
int (*hash_function)(const char * const);
} Hashtable_str;
// Construction and destruction
HASHTABLE_API void tbl_construct(Hashtable_str **table);
HASHTABLE_API void tbl_destruct(Hashtable_str *table);
// Operations
HASHTABLE_API int tbl_insert (Hashtable_str *table, const char * const key, const char * const element); // return the key
HASHTABLE_API int tbl_remove(Hashtable_str *table, const char * const key);
HASHTABLE_API char * tbl_find(Hashtable_str *table, const char * const key); // return the element
HASHTABLE_API int size(Hashtable_str *table); // Return the size
// default hash function
int def_hash(const char * const key);
#ifdef __cplusplus
}
#endif
#endif
Here is the implementation code
// hashtable.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include "hashtable.h"
#include <stdlib.h> // for memcpy
#include <stdio.h>
#include <string.h>
#define SIZE 100
int def_hash(const char * const key)
{
// simply sum the ascii
// values and take modulo
// 100
//int i;
//int sum;
//sum = 0;
//for (i=0; key[i] != '\0'; i++)
// sum += key[i];
//return sum % SIZE;
return 0;
}
// construct a hashtable and return a pointer
HASHTABLE_API void tbl_construct(Hashtable_str **tbl)
{
int i;
Hashtable_str *tbl_ptr;
*tbl = (Hashtable_str*) malloc (sizeof(Hashtable_str*));
tbl_ptr = *tbl;
tbl_ptr->nodes = (Node**) malloc (SIZE * sizeof(Node*));
for (i=0; i < SIZE; i++) tbl_ptr->nodes[i] = NULL;
tbl_ptr->hash_function = &def_hash;
tbl_ptr->num_elements = 0;
tbl_ptr->size = SIZE;
}
HASHTABLE_API void tbl_destruct(Hashtable_str *tbl)
{
void free_tbl_node(Node*); // declare the release function
int i;
for (i=0; i < tbl->size; i++)
{
if (tbl->nodes[i] != NULL)
free_tbl_node(tbl->nodes[i]);
}
}
void free_tbl_node(Node *curr_node)
{
if (curr_node->next != NULL)
free_tbl_node(curr_node->next);
free(curr_node->value);
curr_node->value = NULL;
free(curr_node->key);
curr_node->key = NULL;
//free(curr_node);
//Node *temp = NULL;
//Node *temp2 = NULL;
//temp = temp2 = curr_node;
//while (temp->next != NULL)
//{
// temp2=temp->next;
// free(temp->key);
// free(temp->value);
// free(temp);
// temp=temp2;
//}
}
// table operations
HASHTABLE_API int count(Hashtable_str *tbl) { return tbl->num_elements; }
HASHTABLE_API int size(Hashtable_str *tbl) { return tbl->size; }
HASHTABLE_API int tbl_insert(Hashtable_str *table, const char * const key, const char * const element)
{
int hash;
Node *temp_ptr = NULL;
hash = table->hash_function(key);
// printf("Placing into column %d\n", hash);
if (table->nodes[hash] == NULL)
{
table->nodes[hash] = (Node*) malloc(sizeof(Node*));
temp_ptr = table->nodes[hash];
temp_ptr->next = NULL;
temp_ptr->key = (char*) malloc (strlen(key) + 1 * sizeof(char));
temp_ptr->value = (char*) malloc (strlen(element) + 1 * sizeof(char));
strcpy_s(temp_ptr->key, strlen(key)+1, key);
strcpy_s(temp_ptr->value, strlen(element)+1, element);
table->num_elements += 1;
}
else
{
// Collision!!
temp_ptr = table->nodes[hash];
while (temp_ptr->next != NULL)
temp_ptr = temp_ptr->next;
temp_ptr->next = (Node*) malloc(sizeof(Node));
temp_ptr->next->key = (char*) malloc (strlen(key)+1 * sizeof(char));
temp_ptr->next->value = (char*) malloc (strlen(element)+1 * sizeof(char));
temp_ptr->next->next = NULL;
strcpy_s(temp_ptr->next->key, strlen(key)+1, key);
strcpy_s(temp_ptr->next->value, strlen(element)+1, element);
table->num_elements += 1;
}
// Return the hash value itself for hacking
return hash;
}
HASHTABLE_API int tbl_remove(Hashtable_str *tbl, const char * const key)
{
int hash;
Node *temp_ptr = NULL;
Node *chain = NULL;
hash = tbl->hash_function(key);
if (tbl->nodes[hash] == NULL)
return 1;
else
{
temp_ptr = tbl->nodes[hash];
if (strcmp(key, temp_ptr->key) == 0)
{
// The next node is the node in question
chain = temp_ptr->next;
free(temp_ptr->value);
printf("Deleted the value\n");
free(temp_ptr->key);
printf("Deleted the key\n");
//printf("About to delete the node itself\n");
//free(temp_ptr);
tbl->nodes[hash] = chain;
tbl->num_elements -= 1;
return 0;
}
else
{
while (temp_ptr->next != NULL)
{
if (strcmp(key, temp_ptr->next->key) == 0)
{
// The next node is the node in question
// So grab a pointer to the node after it
// and remove the next node
chain = temp_ptr->next->next;
free(temp_ptr->next->key);
free(temp_ptr->next->value);
//free(temp_ptr->next);
temp_ptr->next = chain;
tbl->num_elements -= 1;
return 0;
}
else
temp_ptr = temp_ptr->next;
}
}
// Couldn't find the node, so declare not existent
return 1;
}
}
HASHTABLE_API char * tbl_find(Hashtable_str *tbl, const char * const key)
{
// Compute the hash for the index
int hash;
Node *temp_ptr = NULL;
hash = tbl->hash_function(key);
if (tbl->nodes[hash] == NULL)
return NULL;
else
{
temp_ptr = tbl->nodes[hash];
if (strcmp(key, temp_ptr->key) != 0)
{
while (temp_ptr->next != NULL)
{
temp_ptr = temp_ptr->next;
if (strcmp(key, temp_ptr->key) == 0)
return temp_ptr->value;
}
}
// Couldn't find the node, so declare not existent
return NULL;
}
}
Here's my main
#include <hashtable.h>
#include <utils.h>
#include <stdio.h>
int main(int argc, char **argv)
{
int i=0;
Hashtable_str *my_table = NULL;
tbl_construct(&my_table);
tbl_insert(my_table, "Daniel", "Student");
tbl_insert(my_table, "Derek", "Lecturer");
//tbl_insert(my_table, "Melvyn", "Lecturer");
tbl_print(my_table);
printf("\nRemoving Daniel...\n");
tbl_remove(my_table, "Daniel");
//tbl_print(my_table);
tbl_destruct(my_table);
my_table = NULL;
scanf_s("%d", &i);
return 0;
}
This is incorrect as allocates the size of a pointer, not a Hashtable_str:
*tbl = (Hashtable_str*) malloc (sizeof(Hashtable_str*));
it should be:
*tbl = malloc(sizeof(Hashtable_str));
Same issue with:
table->nodes[hash] = (Node*) malloc(sizeof(Node*));
See Do I cast the result of malloc?