hashtable issue in C; double free detected in tcache 2 - c

I am coding a hash table with singly linkedList and I have this problem free(): double free detected in tcache 2 I tried to fix it but did'nt make it, the problem its the free() , so could you explain me why I have it, So if anyone can help, so please help me, I'm trying to fix it for hours now...
Thank you.
I've watched some video on youtube and many topics on websitte and also here but I didn't find a solution for mine.
This are my functions:
/**List header */
#ifndef LISTE_H
#define LISTE_H
struct _list_node {
void * data;
struct _list_node *next;
};
typedef struct _list_node s_node;
s_node * list_create(void);
void * list_get_data(s_node * node);
void list_set_data(s_node * node, void * data);
s_node * list_insert(s_node * head, void * data);
s_node * list_append(s_node * head, void * data);
int list_process(s_node * head, int (*fct)(s_node * node, void * param),
void * param, s_node ** last);
s_node * list_ordered_append(s_node ** head, int (*fct)(s_node * node, void * param),
void * param);
s_node * list_remove (s_node * head, void * data);
s_node * list_headRemove(s_node * head);
void * list_destroy(s_node * head);
void afficher_s_node(s_node * list);
int list_is_empty( s_node * node );
unsigned int list_size(s_node * node);
int list_process(s_node * head, int (*fct)(s_node * node, void * param),
void * param, s_node ** last);
#endif
/**** c file list */
#include <stdio.h>
#include <stdlib.h>
#include "list.h"
s_node * list_create(void)
{
return NULL;
}
void * list_get_data(s_node * node)
{
return node->data;
}
void list_set_data(s_node * node, void * data)
{
node->data = data;
}
s_node * list_insert(s_node * head, void * data)
{
s_node * node = (s_node *) malloc(sizeof(s_node));
list_set_data(node, data);
node->next = head;
return node;
}
s_node * list_append(s_node * head, void * data)
{
if (!head) return list_insert(head, data);
s_node * node = head;
while (node->next) {
node = node->next;
}
node->next = (s_node *) malloc(sizeof(s_node));
node->next->next = list_create();
list_set_data(node->next, data);
return head;
}
int list_process(s_node * head, int (*fct)(s_node * node, void * param),
void * param, s_node ** last)
{
if (!head) return 0;
s_node * node;
for (node = head; node; node = node->next) {
if (fct(node, param) == 1) {
*last = node;
return 1;
}
}
return 0;
}
s_node * list_ordered_append(s_node ** head, int (*fct)(s_node * node, void * param),
void * param)
{
// quand elle est vide
if (!(*head)) {
*head = list_insert(*head, param);
return *head;
}
// insertion en tete
s_node * node;
if (fct(*head, param) == 1) {
*head = list_insert(*head, param);
return (*head);
}
// cas general
int res;
for(node = *head; node->next; node = node->next) {
if ((res = fct(node->next, param)) == 1) {
node->next = list_insert(node->next, param);
return node->next;
} else if (res == 0) {
return node->next;
}
}
if (fct(node, param) == 0) return node;
*head = list_append(*head, param);
return node->next;
}
s_node * list_remove (s_node * head, void * data)
{
if (!head) return head;
for (s_node * node = head; node->next; node = node->next) {
if (node->next->data == data) {
s_node * n = node->next->next;
free(node->next);
node->next = n;
break;
}
}
return head;
}
s_node * list_headRemove(s_node * head)
{
if (!head) return head;
s_node * n = head->next;
free(head);
return n;
}
void * list_destroy(s_node * head)
{
while (head)
head = list_headRemove(head);
}
void afficher_s_node(s_node * list)
{
printf("\nliste = [");
while (list) {
printf("%d,", *((int *)(list->data)));
list = list->next;
}
printf("]\n");
return;
}
int list_is_empty( s_node * node ) {
return NULL == node;
}
unsigned int list_size(s_node * node)
{
unsigned int i = 0;
while (node) {
node = node->next;
i++;
}
return i;
}
/*PLUS
int list_process(s_node * head, int (*fct)(s_node * node, void * param),
void * param, s_node ** last)
{
if (!head) return 0;
s_node * node;
for (node = head; node; node = node->next) {
if (fct(node, param) == 1) {
*last = node;
return 1;
}
}
return 0;
}
*/
/* hash table header */
#ifndef HACHAGE_H
#define HACHAGE_H
#include "list.h"
typedef struct {
s_node * node;
unsigned int len;
} super_list;
typedef struct {
super_list * list;
unsigned int len;
} strhash_table;
strhash_table * strhash_table_init(const unsigned int len);
strhash_table * strhash_table_destroy(strhash_table * table);
strhash_table * strhash_table_free(strhash_table * table);
char * strhash_table_add(strhash_table * table, char * str);
strhash_table * strhash_table_remove(strhash_table * table, char * str);
void strhash_table_info(strhash_table * table);
void strhash_print(strhash_table * table);
#endif
/**** c file hash table */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "hachage.h"
#include "list.h"
int hashCode(char * str, const int size_hash_table)
{
int i, cle = 0;
for (i = 0; str[i] != '\0'; i++) {
cle *= 2;
cle += (int) str[i];
}
return cle % size_hash_table;
}
int compare_str_add(s_node *node, void *param)
{
int res = strcmp((char *) node->data, (char *) param);
/*if the first non-matching character in node->data
is lower (in ASCII) than that of param.*/
if (res < 0) return -1;
/*if the first non-matching character in node->data
is greater (in ASCII) than that of param.*/
if (res > 0) return 1;
return 0;//if strings are equal
}
strhash_table * strhash_table_init(const unsigned int len)
{
super_list *list = (super_list *) malloc(sizeof(super_list) * len);
strhash_table * table = (strhash_table *) malloc(sizeof(strhash_table));
if(!table) return NULL;
table->len = len;
if (!list) return NULL;
for (unsigned int i = 0; i < len; i++) {
list[i].node = list_create();
list[i].len = 0;
}
table->list = list;
return table;
}
strhash_table * strhash_table_destroy(strhash_table * table)
{
unsigned int i;
super_list *list;
s_node *node, *next;
for (i = 0; i < table->len; i++) {
list = table->list + i;
node = list->node;
while (node) {
next = node->next;
free(node->data);
free(node);
node = next;
}
}
free(table->list);
free(table);
return table;
}
strhash_table * strhash_table_free(strhash_table * table)
{
unsigned int i;
super_list *list;
for (i = 0; i < table->len; i++) {
list = table->list + i;
if (list->len > 0) {
free(list->node->data);
list_destroy(list->node);
list->len = 0;
return table;
}
}
return table;
}
char * strhash_table_add(strhash_table * table, char * str)
{
char * to_insert = strdup(str);
int index = hashCode(str, table->len);
s_node *ordered_Add = list_ordered_append(&(table->list[index].node), compare_str_add, to_insert);
if (ordered_Add->data == to_insert)
table->list[index].len++;
else
free(to_insert);
return (char *) ordered_Add->data;
}
int find_str_node(s_node *node, void *param)
{
return strcmp((char *) node->data, (char *) param) == 0 ? 1 : 0;
}
strhash_table * strhash_table_remove(strhash_table * table, char * str)
{
const int index = hashCode(str, table->len);
if (table->list[index].len == 0) return table;
s_node *find_node;
const int result = list_process(table->list[index].node, &find_str_node, str, &find_node);
if (result == 1) {
free(find_node->data);
table->list[index].node = list_remove(table->list[index].node, find_node->data);
table->list[index].len--;
}
return table;
}
void strhash_table_info(strhash_table * table)
{
unsigned int i;
unsigned int len, min, max;
float deviation, moy;
len = max = min = table->list[0].len;
for (i = 1; i < table->len; i++) {
if (table->list[i].len > max) max = table->list[i].len;
else if (table->list[i].len < min) min = table->list[i].len;
len += table->list[i].len;
}
moy = (float)len / table->len;
deviation = 0;
for (i = 0; i < table->len; i++) {
deviation += (table->list[i].len - moy) * (table->list[i].len - moy);
}
deviation = (float) sqrt(deviation / table->len);
printf("Table hachage : ");
printf("%p\n",table);
printf("\tNombre total d'élément : " );
printf("%u\n",len );
printf("\tNombre minimum : ");
printf("%u\n", min);
printf("\tNombre maximum : ");
printf("%u\n", max );
printf("\tÉcart type du nombre d'éléments par entrée : ");
printf("%.2f\n", deviation );
return;
}
void strhash_print(strhash_table * table)
{
unsigned int i, j;
super_list *list;
s_node *node;
printf("\nHash table de %p\n", table);
printf("Start\n");
for (i = 0; i < table->len; i++) {
list = table->list + i;
printf("\t%d ---\n", i);
/****/
for (j = 0, node = list->node; j < list->len; j++, node = node->next)
{
printf( "\t\t%d. %s\n", j, (char *) node->data);
}
}
printf("End\n");
return;
}
/**** test file */
strhash_table * test_init(const unsigned int len)
{
strhash_table * table = strhash_table_init(len);
if (!table) {
printf("Tha HashTable hasn't been created\n");
assert(0);
}
printf("***Tha HashTable has been created***\n");
return table;
}
strhash_table * test_destroy(strhash_table * table){
table = strhash_table_destroy(table);
if (table->list->node) {
printf("The HashTable hasn't been destroyed (%p)\n", table->list->node);
assert(0);
}
printf("The HashTable has been destroyed\n");
return NULL;
}
int main(void)
{
strhash_table * table =strhash_table_init(10);
strhash_print(table);
strhash_table_add(table, "ele1");
strhash_table_add(table, "ele2");
strhash_table_add(table, "ele3");
strhash_table_add(table, "ele4");
strhash_table_add(table, "ele5");
//strhash_table_remove(table,"ele1");
//strhash_table_free(table);
test_destroy(table);
return 0;
}
Thank you in advance ^^

You should move list_destroy(list->node); outside the inner loop. You are freeing the node list multiple times inside a loop where you iterate on the node links.
Here is a modified version:
strhash_table *strhash_table_destroy(strhash_table *table) {
unsigned int i;
super_list *list;
s_node *node;
for (i = 0; i < table->len; i++) {
list = table->list + i;
for (node = list->node; node != NULL; node = node->next) {
free(node->data);
}
list_destroy(list->node);
}
free(table->list);
free(table);
return table;
}
void list_destroy(s_node *head) {
while (head) {
head = list_headRemove(head);
}
}
s_node *list_headRemove(s_node *head) {
if (!head) return head;
s_node *n = head->next;
free(head);
return n;
}
UPDATE
In the code posted, there are conflicting versions of functions list_destroy and list_headRemove, furthermore there are 2 calls to free(node); in the second function list_destroy, both of which are useless since node is a null pointer when the while loop exits.
UPDATE 2
There is a problem in strhash_table_free: you free list->node but you do not update list->node, so the list is freed a second time in strhash_table_destroy where list->len is not tested.
The field len in super_list seems redundant. You should just test if the node member is NULL and set it to NULL when the list is freed.
UPDATE 3
The final post is hardly minimal and does not show the problem... but I found some issues:
strhash_table_destroy returns table after freeing it: this is bad because table is now an invalid pointer. strhash_table_destroy should not return anything.
test_destroy dereferences table after strhash_table_destroy has freed it. This has undefined behavior. Remove this test function, just call strhash_table_destroy from main().
you free node->data in strhash_table_remove before passing it to list_remove, which is bad because node->data has become invalid.
worse: list_remove() does not test is the head node should be removed. In a minimal test case with a single element in the hash table, "ele1" is the head node, hence this node remains in the list, the len is decremented and becomes out of sync and the node has an invalid data pointer which will strhash_table_destroy will attempt to free, causing the double free issue.
strhash_table_free seems incorrect and inconsistent with strhash_table_destroy.
There are probably other issues in the code.
Here is a modified version with some simplifications and fixes:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
/**List header */
#ifndef LISTE_H
#define LISTE_H
struct _list_node {
void *data;
struct _list_node *next;
};
typedef struct _list_node s_node;
s_node *list_create(void);
void *list_get_data(s_node *node);
void list_set_data(s_node *node, void *data);
s_node *list_insert(s_node *head, void *data);
s_node *list_append(s_node *head, void *data);
s_node *list_process(s_node *head, int (*fct)(s_node *node, void *param), void *param);
s_node *list_ordered_append(s_node **head, int (*fct)(s_node *node, void *param), void *param);
s_node *list_headRemove(s_node *head);
s_node *list_remove(s_node *head, void *data);
void list_destroy(s_node *head);
void afficher_s_node(s_node *list);
int list_is_empty( s_node *node );
unsigned int list_size(s_node *node);
#endif
/**** c file list */
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
//#include "list.h"
s_node *list_create(void) {
return NULL;
}
void *list_get_data(s_node *node) {
return node->data;
}
void list_set_data(s_node *node, void *data) {
node->data = data;
}
s_node *list_insert(s_node *head, void *data) {
s_node *node = (s_node *)malloc(sizeof(s_node));
if (node) {
list_set_data(node, data);
node->next = head;
return node;
} else {
return head;
}
}
s_node *list_append(s_node *head, void *data) {
if (!head) return list_insert(head, data);
s_node *node = head;
while (node->next) {
node = node->next;
}
node->next = list_insert(NULL, data);
return head;
}
s_node *list_process(s_node *head, int (*fct)(s_node *node, void *param), void *param) {
for (s_node *node = head; node; node = node->next) {
if (fct(node, param) == 1) {
return node;
}
}
return NULL;
}
s_node *list_ordered_append(s_node **head, int (*fct)(s_node *node, void *param), void *param) {
s_node *node;
int res;
// empty list
if (!*head) {
return *head = list_insert(*head, param);
}
// insert at head
res = fct(*head, param);
if (res > 0) {
return *head = list_insert(*head, param);
}
if (res == 0) {
return *head;
}
// generic case
for (node = *head; node->next; node = node->next) {
res = fct(node->next, param);
if (res > 1) {
return node->next = list_insert(node->next, param);
}
if (res == 0) {
return node->next;
}
}
// append node
return node->next = list_insert(NULL, param);
}
s_node *list_headRemove(s_node *head) {
if (head) {
s_node *n = head->next;
free(head);
return n;
} else {
return NULL;
}
}
s_node *list_remove(s_node *head, void *data) {
if (!head) return head;
if (head->data == data) {
head = list_headRemove(head);
} else {
for (s_node *node = head; node->next; node = node->next) {
if (node->next->data == data) {
node->next = list_headRemove(node->next);
break;
}
}
}
return head;
}
void list_destroy(s_node *head) {
while (head)
head = list_headRemove(head);
}
int list_is_empty(s_node *node) {
return node == NULL;
}
unsigned int list_size(s_node *node) {
unsigned int i = 0;
while (node) {
node = node->next;
i++;
}
return i;
}
/* hash table header */
#ifndef HACHAGE_H
#define HACHAGE_H
//#include "list.h"
typedef struct {
s_node *node;
unsigned int len;
} super_list;
typedef struct {
super_list *list;
unsigned int len;
} strhash_table;
strhash_table *strhash_table_init(const unsigned int len);
void strhash_table_destroy(strhash_table *table);
strhash_table *strhash_table_free(strhash_table *table);
char *strhash_table_add(strhash_table *table, const char *str);
int strhash_table_remove(strhash_table *table, const char *str);
void strhash_table_info(strhash_table *table);
void strhash_print(strhash_table *table);
#endif
/**** c file hash table */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
//#include "hachage.h"
//#include "list.h"
int hashCode(const char *str, unsigned int size_hash_table) {
unsigned int i, cle = 0;
for (i = 0; str[i] != '\0'; i++) {
cle *= 2;
cle += (int)str[i];
}
return cle % size_hash_table;
}
int compare_str_add(s_node *node, void *param) {
/* return <0 if node->data is before param, >0 if after, =0 if strings are equal */
return strcmp((const char *)node->data, (const char *)param);
}
strhash_table *strhash_table_init(const unsigned int len) {
strhash_table *table = (strhash_table *)malloc(sizeof(strhash_table));
super_list *list = (super_list *)malloc(sizeof(super_list) * len);
if (!table || !list) {
free(table);
free(list);
return NULL;
}
for (unsigned int i = 0; i < len; i++) {
list[i].node = list_create();
list[i].len = 0;
}
table->list = list;
table->len = len;
return table;
}
void strhash_table_destroy(strhash_table *table) {
for (unsigned int i = 0; i < table->len; i++) {
super_list *list = table->list + i;
s_node *node = list->node;
while (node) {
s_node *next = node->next;
free(node->data);
free(node);
node = next;
}
list->node = NULL;
}
free(table->list);
free(table);
}
char *strhash_table_add(strhash_table *table, const char *str) {
char *to_insert = strdup(str);
int index = hashCode(str, table->len);
s_node *ordered_Add = list_ordered_append(&table->list[index].node, compare_str_add, to_insert);
if (ordered_Add->data == to_insert) {
/* node was inserted: increase len */
table->list[index].len++;
} else {
/* node already present: free new data */
free(to_insert);
}
return (char *)ordered_Add->data;
}
int find_str_node(s_node *node, void *param) {
return strcmp((const char *)node->data, (const char *)param) == 0 ? 1 : 0;
}
// return 1 if successful
int strhash_table_remove(strhash_table *table, const char *str) {
int index = hashCode(str, table->len);
s_node *find_node = list_process(table->list[index].node, find_str_node, (void *)(uintptr_t)str);
if (find_node) {
/* node was found: free node and data */
void *data = find_node->data;
table->list[index].node = list_remove(table->list[index].node, data);
table->list[index].len--;
free(data);
return 1;
}
return 0;
}
void strhash_table_info(strhash_table *table) {
unsigned int i;
unsigned int len, min, max;
double deviation, moy;
len = max = min = table->list[0].len;
for (i = 1; i < table->len; i++) {
if (table->list[i].len > max) max = table->list[i].len;
else if (table->list[i].len < min) min = table->list[i].len;
len += table->list[i].len;
}
moy = (double)len / table->len;
deviation = 0;
for (i = 0; i < table->len; i++) {
deviation += (table->list[i].len - moy) * (table->list[i].len - moy);
}
deviation = sqrt(deviation / table->len);
printf("Table hachage : ");
printf("%p\n", (void *)table);
printf("\tNombre total d'élément : " );
printf("%u\n",len );
printf("\tNombre minimum : ");
printf("%u\n", min);
printf("\tNombre maximum : ");
printf("%u\n", max );
printf("\tÉcart type du nombre d'éléments par entrée : ");
printf("%.2f\n", deviation);
return;
}
void strhash_print(strhash_table *table) {
unsigned int i, j;
super_list *list;
s_node *node;
printf("\nHash table de %p\n", (void *)table);
printf("Start\n");
for (i = 0; i < table->len; i++) {
list = table->list + i;
printf("\t%d ---\n", i);
/****/
for (j = 0, node = list->node; j < list->len; j++, node = node->next) {
printf( "\t\t%d. %s\n", j, (char *)node->data);
}
}
printf("End\n");
}
/**** test file */
int main(void) {
strhash_table *table = strhash_table_init(10);
strhash_print(table);
strhash_table_add(table, "ele1");
strhash_table_remove(table, "ele1");
strhash_table_add(table, "ele1");
strhash_table_add(table, "ele2");
strhash_table_add(table, "ele3");
strhash_table_add(table, "ele4");
strhash_table_add(table, "ele5");
strhash_table_remove(table, "ele1");
strhash_print(table);
strhash_table_destroy(table);
return 0;
}

A cleaner way to do it in my opinion assuming you don't reuse list_headRemove and list_headRemove :
strhash_table *strhash_table_destroy(strhash_table *table) {
unsigned int i;
super_list *list;
s_node *node, *next;
for (i = 0; i < table->len; i++) {
list = table->list + i;
node = list->node;
while (node) {
next = node->next;
free(node->data);
free(node);
node = next;
}
}
free(table->list);
free(table);
return table; /* This pointer is not valid anymore be careful */
}

Related

How to declare and access a pointer to a member of a member struct in C?

So, I am relatively new to C and trying to implement a Queue using Linked Lists. Here is some code I wrote with help from the internet.
#include <stdio.h>
#include <stdlib.h>
#define pscan(prompt, x) printf(prompt); scanf("%d", &x)
#define nl() printf("\n");
typedef struct Node {
int data;
struct Node* next;
} Node;
typedef struct LinkedList {
Node* head;
Node* tail;
int size;
int (*add) (struct LinkedList*, int, int);
int (*append) (struct LinkedList*, int);
int (*get) (struct LinkedList*, int);
int (*remove) (struct LinkedList*, int);
void (*display_list) (struct LinkedList*);
Node* (*createNode) (int);
} LinkedList;
int add (LinkedList* self, int data, int position);
int append (LinkedList* self, int data);
int get (LinkedList* self, int position);
int rmv (LinkedList* self, int position);
void display_list (LinkedList* self);
LinkedList createLinkedList ();
Node* createNode (int data);
int add(LinkedList* self, int data, int position)
{
if (position > self->size || position < 0)
{
printf("Index out of bounds\n");
return 0;
}
Node* newNode = self->createNode(data);
Node* head = self->head;
Node* tail = self->tail;
if (position == 0)
{
if (head == NULL) self->head = newNode;
else
{
if (tail == NULL) tail = head;
newNode->next = head;
self->head = newNode;
}
self->size++;
}
else if (position == self->size)
{
if (head == NULL) self->head = newNode;
else
{
if (tail == NULL) tail = head;
tail->next = newNode;
self->tail = newNode;
}
self->size++;
}
else
{
Node* prev = head;
for(int i = 0; i < position-1; i++)
{
prev = prev->next;
}
Node* node = prev->next;
prev->next = newNode;
newNode->next = node;
self->size++;
}
return 0;
}
int append(LinkedList* self, int data)
{
return self->add(self, data, self->size);
}
int get(LinkedList* self, int position)
{
if (self->size == 0)
{
printf("The list is empty.");
return 0;
}
else if (position >= self->size || position < 0)
{
printf("Index out of bound.");
return 0;
}
if (position == 0) return self->head->data;
else if (position+1 == self->size) return self->tail->data;
else
{
Node* node = self->head;
for(int i = 0; i < position; i++) node = node->next;
return node->data;
}
}
int rmv (LinkedList* self, int position)
{
int dt;
if (self->size == 0)
{
printf("The list is empty.");
return 0;
}
else if (position >= self->size || position < 0)
{
printf("Index out of bound");
return 0;
}
if (position == 0)
{
Node* head = self->head;
Node* next = head->next;
self->head = next;
dt = head->data;
free(head);
self->size--;
}
else if (position+1 == self->size)
{
Node* node = self->head;
Node* tail = self->tail;
for(int i = 0; i < self->size-2; i++) node = node->next;
node->next = NULL;
self->tail = node;
dt = tail->data;
free(tail);
self->size--;
}
else
{
Node* prev = self->head;
Node* next;
Node* node;
for(int i = 0; i < position-1; i++) prev = prev->next;
node = prev->next;
next = node->next;
prev->next = next;
dt = node->data;
free(node);
self->size--;
}
return dt;
}
void display_list(LinkedList* self)
{
if (self->size == 0) printf("This list is empty.\n\n");
else
{
Node* node = self->head;
printf("[");
for (int i = 0; i < self->size; i++)
{
if (i > 0) printf(", ");
printf("%d", node->data);
node = node->next;
}
printf("]\n\n");
}
}
Node* createNode (int data)
{
Node* node = (Node*) malloc(sizeof(Node));
node->data = data;
node->next = NULL;
return node;
}
LinkedList createLinkedList ()
{
LinkedList l;
l.head = NULL;
l.tail = NULL;
l.add = &add;
l.append = &append;
l.get = &get;
l.remove = &rmv;
l.display_list = &display_list;
l.createNode = &createNode;
l.size = 0;
return l;
}
typedef struct queue
{
LinkedList items;
int *size;
int (*enqueue) (struct queue*, int);
int (*dequeue) (struct queue*);
int (*peek) (struct queue*, int);
void (*display) (struct queue*);
} Queue;
Queue CreateQueue();
int enqueue(Queue* self, int item);
int dequeue(Queue* self);
int peek(Queue* self, int pos);
void display(Queue* self);
Queue CreateQueue()
{
Queue q;
q.items = createLinkedList();
q.size = &(q.items.size);
q.enqueue = &enqueue;
q.dequeue = &dequeue;
q.peek = &peek;
q.display = &display;
return q;
}
int enqueue(Queue* self, int item)
{
self->items.append(&(self->items), item);
return 1;
}
int dequeue(Queue* self)
{
return self->items.remove(&(self->items), 0);
}
int peek(Queue* self, int pos)
{
return self->items.get(&(self->items), pos);
}
void display(Queue* self)
{
printf("%d items in queue.\n", *(self->size));
self->items.display_list(&(self->items));
}
void main()
{
Queue q = CreateQueue();
q.enqueue(&q, 3);
q.enqueue(&q, 7);
q.enqueue(&q, 4);
q.display(&q);
int item = q.dequeue(&q);
printf("Dequeued: %d\n", item);
q.display(&q);
q.enqueue(&q, 14);
q.display(&q);
}
The part I'm having an issue with is making the Queue's size pointer point to the LinkedList's size integer and then accessing that value.
On compiling and running, I get this:
Output from the above code
Thanks in advance.
The problem is in createQueue:
Queue CreateQueue()
{
Queue q;
q.items = createLinkedList();
q.size = &(q.items.size);
q.enqueue = &enqueue;
q.dequeue = &dequeue;
q.peek = &peek;
q.display = &display;
return q;
}
You set q.size to point to q.items.size. This is a pointer to a local variable. You then return a copy of q, but the size member now points to a local that doesn't exist. Dereferencing a pointer to a variable whose lifetime has ended triggers undefined behavior.
There's no need for the size element in Queue. Just access the size element of the items member directly.

Can't find memory leak in linked lists function "16 bytes in 1 blocks are definitely lost in loss record 1 of 1"

I am learning C and wrote a few functions to work with linked lists in C. However, I have a memory leak (I guess because of the reassignment of the node* list in lines 28 and 29) and was looking for a way to solve it.
My code:
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
int number;
struct node *next;
}
node;
node *declare(int value);
int count(node *list);
node *lead(node *list, int value);
void trail(node *list, int value);
node *append(node *list, int value, int index);
node *fetch_node(node *list, int index);
int fetch(node *list, int index);
int *list_to_array(node *list);
node *array_to_list(int array[], int range);
void free_list(node *list);
node *delete(node *list, int index);
void print(node *list);
int main(void)
{
node *list = declare(1);
list = lead(list, -1);
trail(list, 2);
trail(list, 44);
list = delete(list, 0);
append(list, 232, 1);
int *array = list_to_array(list);
node *list_new = array_to_list(array, 4);
printf("%d\n", fetch(list_new, 3));
print(list);
free_list(list);
free_list(list_new);
free(array);
}
node *declare(int value)
{
node *n = malloc(sizeof(node));
n->number = value;
n->next = NULL;
return n;
}
int count(node *list)
{
node *tmp = list;
int count = 1;
while (tmp->next != NULL)
{
tmp = tmp->next;
count++;
}
return count;
}
node *lead(node *list, int value)
{
node *n = declare(value);
node *tmp = list;
n->next = tmp;
return n;
}
void trail(node *list, int value)
{
node *n = declare(value);
node *tmp = list;
while (tmp->next != NULL)
{
tmp = tmp->next;
}
tmp->next = n;
}
node *append(node *list, int value, int index)
{
if (index == 0)
{
return lead(list, value);
}
else
{
int range = count(list);
node *n = declare(value);
node *prev = fetch_node(list, index - 1);
node *follow = fetch_node(list, index);
prev->next = n;
n->next = follow;
return list;
}
}
node *fetch_node(node *list, int index)
{
node *tmp = list;
if (index < count(list))
{
for (int i = 0; i < index; i++)
{
tmp = tmp->next;
}
}
else
{
fprintf(stderr, "VALUE IN FETCH OUT OF RANGE, RETURNING POINTER TO LIST\n");
}
return tmp;
}
int fetch(node *list, int index)
{
node *fetched = fetch_node(list, index);
return fetched->number;
}
node *delete(node *list, int index)
{
if (index == 0)
{
node *follow = list->next;
list = list->next;
}
else
{
node *fetched = fetch_node(list, index);
node *prev, *follow;
if (index > 0)
{
prev = fetch_node(list, index - 1);
}
else
{
prev = list;
}
int range = count(list);
if (index != range - 1 && index < range)
{
follow = fetch_node(list, index + 1);
}
else
{
follow = NULL;
}
prev->next = follow;
}
return list;
}
int *list_to_array(node *list)
{
int range = count(list);
int *array = malloc(sizeof(int) * range);
for (int i = 0; i < range; i++)
{
array[i] = fetch(list, i);
}
return array;
}
node *array_to_list(int array[], int range)
{
node *list = declare(array[0]);
for (int i = 1; i < range; i++)
{
trail(list, array[i]);
}
return list;
}
void free_list(node *list)
{
int range = count(list);
node *tmp = list;
node *del;
for (int i = 0; i < range; i++)
{
del = tmp;
tmp = tmp->next;
free(del);
}
}
void print(node *list)
{
int range = count(list);
printf("[");
for (int i = 0; i < range; i++)
{
int value = fetch(list, i);
printf("%d", value);
if (i != range - 1)
{
printf(", ");
}
}
printf("]\n");
}
And this is Valgrind output:
==18184== 16 bytes in 1 blocks are definitely lost in loss record 1 of 1
==18184== at 0x4C31B0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==18184== by 0x4007C4: declare (linked_lists.c:45)
==18184== by 0x400806: lead (linked_lists.c:65)
==18184== by 0x4006F3: main (linked_lists.c:29)
Any ideas?
Your delete function is creating memory leak because it doesn't free the deleted node.
Add code to free that.
node *delete(node *list, int index)
{
if (index == 0)
{
node *follow = list->next;
// list = list->next;
free(list); // free deleted node
list = follow;
}
else
{
node *fetched = fetch_node(list, index);
node *prev, *follow;
if (index > 0)
{
prev = fetch_node(list, index - 1);
}
else
{
prev = list;
}
int range = count(list);
if (index != range - 1 && index < range)
{
follow = fetch_node(list, index + 1);
}
else
{
follow = NULL;
}
free(prev->next); // free deleted node
prev->next = follow;
}
return list;
}

Unable to delete value from HashTable in C

I'm trying to delete a value from hash table, the code works when I delete a value from the array where the linked list size is one, then segfaults if the size is greater than 1.
typedef struct hash {
char *key;
char *value;
struct hash *next;
} hashTable;
// generate hash code
unsigned int hashCode(char *key) {
int sum;
int i;
sum = 0;
i = 0;
while (key[i])
sum += key[i++];
return sum % MAX_HASH;
}
// get hash item size
int hash_size(hashTable *head) {
int i;
hashTable *list;
i = 0;
list = head;
if (list) {
while (list != NULL) {
i++;
list = list->next;
}
}
return (i);
}
// free item
void free_hash(hashTable *item) {
free(item->key);
free(item->value);
free(item);
}
// function for deleting item from hash table
void deleteItem(hashTable *table[], char *key) {
hashTable *head = table[hashCode(key)];
hashTable *tmp = head;
hashTable *prev = NULL;
if (!head)
return;
if (hash_size(tmp) == 1) {
table[hashCode(key)] = 0;
free_hash(tmp);
return;
}
while (strcmp(tmp->key, key) != 0 && tmp->next != NULL) {
prev = tmp;
tmp = tmp->next;
}
if (strcmp(tmp->key, key) == 0) {
if (prev)
prev->next = tmp->next;
else
head = tmp->next;
free_hash(tmp);
}
}
// function for inserting item into the table
void insert(hashTable *table[], char *key, char *value) {
hashTable *tmp;
hashTable *item;
unsigned int code;
item = (hashTable *)malloc(sizeof(hashTable));
if (!item)
return;
item->key = (char *)malloc(sizeof(char) * strlen(key) + 1);
item->value = (char *)malloc(sizeof(char) * strlen(value) + 1);
item->next = NULL;
code = hashCode(key);
strcpy(item->key, key);
strcpy(item->value, value);
if (!table[code])
table[code] = item;
else {
tmp = table[code];
item->next = tmp;
table[code] = item;
}
}
// displaying items
void display(hashTable *table[]) {
int i = 0;
hashTable *tmp;
while (i < MAX_HASH) {
if (table[i] != NULL) {
tmp = table[i];
if (hash_size(tmp) == 1)
printf("%s=%s\n", tmp->key, tmp->value);
else {
while (tmp != NULL) {
printf("%s=%s\n", tmp->key, tmp->value);
tmp = tmp->next;
}
}
}
i++;
}
}
int main(int argc, char const *argv[]) {
hashTable *table[MAX_HASH];
memset(table, 0, MAX_HASH * sizeof(hashTable *));
insert(table, "Bart", "first");
insert(table, "Lisa", "Second");
insert(table, "Foo", "bar");
deleteItem(table, "Lisa");
display(table);
return 0;
}
There are many issues in your code:
do include the standard header files, and define HASH_MAX:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define HASH_MAX 1027
the type hashTable is confusing: it is really an entry list, the hash table itself is the array.
the while loops are error prone: use the much preferred for loops where the initialization, test and increment of the loop index are conveniently located on the same line:
for (int i = 0; i < HASH_MAX; i++) {
// printf hashTable[i]
}
I know the local style conventions at 42 explicitly exclude the for loop, but you should lobby against this questionable choice.
there is no need to special case hash_size(tmp) == 1 in display_table()
there is no need to cast the return value of malloc(). sizeof(char) is 1 by definition. You could use strdup() to duplicate C strings.
in deleteItem() you always remove the entry if it is alone: this is incorrect if the entry has a different key. Furthermore, you do not link the previous node or the table slot to the next element of the list.
Here is a corrected version of this function:
// function for deleting item from hash table
void deleteItem(hashTable *table[], const char *key) {
hashTable **link = &table[hashCode(key)];
while (*link) {
hashTable *tmp = *link;
if (strcmp(tmp->key, key) == 0) {
*link = tmp->next; // unlink the list node
free_hash(tmp);
break; // remove this if you mean for deleteItem to remove all matching nodes
} else {
link = &(*link)->next;
}
}
}
Here is a simplified version of the whole program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_HASH 1027
typedef struct HashItem {
char *key;
char *value;
struct HashItem *next;
} HashItem;
// generate hash code
unsigned int hashCode(const char *key) {
unsigned int sum = 0;
for (int i = 0; key[i]; i++) {
sum += (unsigned char)key[i] * (i + 1);
}
return sum % MAX_HASH;
}
// free item
void freeItem(HashItem *item) {
free(item->key);
free(item->value);
free(item);
}
// function for deleting item from hash table
void deleteItem(HashItem *table[], const char *key) {
HashItem **link = &table[hashCode(key)];
while (*link) {
HashItem *tmp = *link;
if (strcmp(tmp->key, key) == 0) {
*link = tmp->next; // unlink the list node
freeItem(tmp);
break;
} else {
link = &(*link)->next;
}
}
}
// function for inserting item into the table
void insertItem(HashItem *table[], const char *key, const char *value) {
unsigned int code = hashCode(key);
HashItem *item = malloc(sizeof(*item));
if (item != NULL) {
item->key = strdup(key);
item->value = strdup(value);
item->next = table[code];
table[code] = item;
}
}
// displaying items
void displayHashTable(HashItem *table[]) {
for (int i = 0; i < MAX_HASH; i++) {
for (HashItem *tmp = table[i]; tmp; tmp = tmp->next) {
printf("%s=%s\n", tmp->key, tmp->value);
}
}
}
int main(int argc, char const *argv[]) {
HashItem *table[MAX_HASH] = { 0 };
insertItem(table, "Bart", "first");
insertItem(table, "Lisa", "Second");
insertItem(table, "Foo", "bar");
deleteItem(table, "Lisa");
displayHashTable(table);
return 0;
}

Trouble adding vertexes to linked list

There is something wrong with my add_vertex
In valgrind I am getting an "Uninitialised value was created by a heap allocation" error
at 0x4C27A2E: malloc (vg_replace_malloc.c:270)
by 0x400892: add_vertex (graph.c:56)
typedef struct {
char *dest_name;
int cost;
} dest_cost;
typedef struct Node {
char *name;
dest_cost *destcost;
int num_dest;
struct Node *next;
} Node;
typedef struct {
int size;
struct Node *node;
} Graph;
INITIALIZE GRAPH
void init_graph(Graph *graph) {
if (graph != NULL)
graph->size = 0;
}
ADD VERTEX
int add_vertex(Graph *graph, const char new_vertex[]) {
Node *next, *temp, *new_node;
int i;
if (has_vertex(*graph, new_vertex))
return 0;
new_node = malloc(sizeof(Node));
new_node->name = malloc(strlen(new_vertex) + 1);
strcpy(new_node->name, new_vertex);
new_node->num_dest = 0;
if (graph->size != 0) {
temp = graph->node;
if (strcmp(temp->name, new_vertex) > 0) {
new_node->next = temp;
graph->node = new_node;
graph->size++;
return 1;
}
else for (i = 1; i < graph->size; i++) {
next = temp->next;
if (strcmp(next->name, new_vertex) > 0) {
new_node->next = next;
temp->next = new_node;
graph->size++;
return 1;
}
}
temp->next = new_node;
graph->size++;
return 1;
}
graph->node = new_node;
graph->size++;
return 1;
}
ADDED: CLEAR GRAPH
void clear_graph(Graph *graph) {
int i;
Node *next, *n = graph->node;
if (graph != NULL) {
for (i = 0; i < graph->size; i++) {
next = n->next;
free(n);
n = next;
}
free(graph);
}
}
ADDED TEST
Graph graph;
const char *vertices_to_add[]= {"koala", "platypus", "snake", "salamander",
"gecko", "frog", "dog", "hedgehog"};
int i;
init_graph(&graph);
for (i= 0; i < sizeof(vertices_to_add) / sizeof(vertices_to_add[0]); i++)
add_vertex(&graph, vertices_to_add[i]);
clear_graph(&graph);

Inserting and Removing from Linked List

This is a hashtable implementation.
I have the insert kinda working but how do I return the linked list?
I know that the remove is not done yet but I understand the concept, my problem is returning the adjusted list.
I tried to make the hashtable a global variable but the programming would force when I ran it.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <assert.h>
#include <string.h>
struct node {
char * data;
struct node * next;
};
struct hashtable {
struct node ** table;
int size;
int nentries;
};
struct hashtable * hashtable_new(int size) {
struct hashtable * result;
result = malloc(sizeof(struct hashtable));
result -> size = size;
result -> nentries = 0;
result -> table = malloc(sizeof(struct node) * size);
int i = 0;
for (i = 0; i < result->size; i++) {
result->table[i] = NULL;
// result->table[i]->data = NULL;
}
return result;
}
unsigned hash_string(struct hashtable *this, char * str) {
unsigned hash = 0;
int i = 0;
for ( i = 0; str[i] != '\0'; i++ ) {
hash = hash * 37 + str[i];
}
//return hash;
return hash % this-> size;
}
void hashtable_free(struct hashtable * this) {
int i;
struct node *table_nodes, *current, *next;
for(i = 0; i<this->size; i++) {
table_nodes = this->table[i];
current = table_nodes;
while (current != NULL){
next = current->next;
free(current);
current = next;
}
this->table[i] = NULL;
}
free(&this->table);
free(&this->size);
free(&this->nentries);
free(this);
}
void hashtable_insert(struct hashtable * table, char * string) {
struct node * new_node;
unsigned index = hash_string(table, string);
if(table->table[index] == NULL) {
printf("\nIndex: %d", index);
new_node = malloc(sizeof(struct node));
new_node -> next = table->table[index];
new_node -> data = string;
printf("\nData: %s", new_node->data);
table -> table[index] = new_node;
table -> nentries++;
printf("\n");
} else {
new_node = malloc(sizeof(struct node));
new_node->data = string;
new_node->next = NULL;
struct node * current = table->table[index];
struct node * next;
int size = 1;
while (current != NULL) {
next = current->next;
//if(current->data == string){
//return;
//}
if(current-> next == NULL){
//last element in list
current->next = new_node;
table->nentries++;
size++;
printf("\nIndex: %d", index);
printf("\nSize: %d", size);
printf("\nData: %s", current->next->data);
printf("\n");
return;
}
current = next;
size++;
}
}
}
void remove_hash(struct hashtable * this, char * item) {
//unsigned index = hash_string(this, item);
}
int lookup(struct hashtable * this, char * item) {
struct node *temp;
unsigned int index = hash_string(this, item);
temp = this->table[index];
while(temp != NULL) {
// do something
printf("%s, ", temp->data);
if(temp->data == item) {
printf("found %s\n", temp->data);
}
temp = temp->next;
}
return 0;
}
void print(struct hashtable * this) {
int i = 0;
printf("\n Size %d \n", this->size);
if(this == NULL) {
printf("Please construct the hashtable");
return;
}
for (i = 0; i < this->size; i++) {
if(this->table[i] == NULL) {
printf("\n %d: <empty>", i);
} else {
printf("\n %d: %s ", i, this->table[i]->data);
if(this->table[i]->next != NULL) {
printf("%s ", this->table[i]->next->data);
}
}
}
}
int main(int argc, char **argv) {
//struct node *theNode;
struct hashtable *theHash;
theHash = hashtable_new(9);
hashtable_insert(theHash, "I");
hashtable_insert(theHash, "am");
hashtable_insert(theHash, "a");;
hashtable_insert(theHash, "fish");
hashtable_insert(theHash, "glub");
print(theHash);
hashtable_insert(theHash, "glub");
lookup(theHash, "I");
print(theHash);
//printf("\n\n\n");
hashtable_free(theHash);
//print(theHash);
return 0;
}
Since C doesn't let you pass by reference, you can try returning the hashtable then reassigning your variable with the result of hashtable_insert:
struct hashtable *hashtable_insert(struct hashtable *table, char *string) {
// awesome code here
return current;
}
And then call it with:
theHash = hashtable_insert(theHash, "Wow!");

Resources