segmentation fault testing linked list - c

I am trying to build and test a linked list in C. But I can't seem to figure out why I am getting segmentation fault from running the test (test_linked_list.c). The problem seems to be from the list_delete function when running gdb, but I can't find where the problem is. Why is this wrong?
linkedlist.c:
#include <stdio.h>
#include <string.h>
#include "linked_list.h"
void list_init(list_t *h) {
*h = NULL;
}
int list_size(const list_t *h) {
node_t *p = *h;
int r = 0;
do {
r += 1;
p = p->next;
} while (p);
return r;
}
int list_empty(const list_t *h) {
return (*h == NULL);
}
void list_insert(list_t *h, node_t *n) {
n->next = *h;
*h = n;
}
node_t *list_find(const list_t *h, int id) {
node_t *p = *h;
while (p) {
if (p->id == id)
return p;
p = p->next;
}
}
node_t *list_find_before(const list_t *h, int id) {
node_t *p = *h;
while (p && p->next) {
if (p->next->id == id)
return p;
p = p->next;
}
return NULL;
}
node_t *list_delete(list_t *h, int id) {
node_t *r = NULL;
if (*h && (*h)->id == id) {
r = *h;
*h = NULL;
return r;
}
// Here we have a syntax bug
node_t *p = list_find_before(h, id);
if (p) {
r = p->next;
p->next = p->next->next;
r->next = NULL;
}
return r;
}
void print_list(const list_t *h) {
node_t *p = *h;
while (p) {
printf("%d: %s says %s\n", p->id, p->name, p->msg);
p = p->next;
}
}
test_linked_list.c:
#include <stdlib.h>
#include "linked_list.h"
#include <string.h>
#include <assert.h>
#include <stdio.h>
void test_delete_one() {
list_t h;
list_init(&h);
node_t n;
n.id = 0;
strcpy(n.name, "hello");
strcpy(n.msg, "world");
list_insert(&h, &n);
node_t *f = list_delete(&h, 0);
assert(f == &n);
}
void test_delete() {
list_t h;
list_init(&h);
node_t n[3];
int i;
for (i = 0; i < 3; i++) {
n[i].id = i;
list_insert(&h, &n[i]);
}
list_delete(&h, 1);
assert(list_size(&h) == 2);
}
void core_dump_test() {
int size = 0;
list_t h;
list_init(&h);
size = list_size(&h);
printf("list size is: %d\n", size);
}
int main() {
test_delete();
test_delete_one();
core_dump_test();
printf("Pass\n");
}

There are wrong several functions.
For example list_size
int list_size(const list_t *h) {
node_t *p = *h;
int r = 0;
do {
r += 1;
p = p->next;
} while (p);
return r;
}
can invoke undefined behavior for an empty list.
Or another example. The function list_find
node_t *list_find(const list_t *h, int id) {
node_t *p = *h;
while (p) {
if (p->id == id) return p;
p = p->next;
}
}
returns nothin in case when a specified value is not found in the list.
Or the function list_find_before
node_t *list_find_before(const list_t *h, int id) {
node_t *p = *h;
while (p && p->next) {
if (p->next->id == id) return p;
p = p->next;
}
return NULL;
}
ignores the first node of the list.
And so on.
As for the function list_delete when even in its beginning it has a bug setting *h to NULL
node_t *list_delete(list_t *h, int id) {
node_t *r = NULL;
if (*h && (*h)->id == id) {
r = *h;
*h = NULL;
return r;
}
//...
Pay attention to that nodes must be allocated dynamically. Otherwise your list does not make sense.

The reason you get a segmentation fault in core_dump_test() is list_size cannot handle an empty list: it reads p->next without checking for p != NULL. As a rule of thumb, you should avoid do/while loops as they tend to hide bugs efficiently.
Here is a modified version:
int list_size(const list_t *h) {
int r = 0;
for (const node_t *p = *h; p; p = p->next) {
r += 1;
}
return r;
}
Here are modified versions of other functions with problems:
list_find has a missing return statement:
node_t *list_find(const list_t *h, int id) {
for (const node_t *p = *h; p; p = p->next) {
if (p->id == id)
return p;
}
return NULL; // was missing
}
list_delete truncates the list if the matching node is the first one. Also the syntax bug comes from your compiler rejecting the c99 syntax.
node_t *list_delete(list_t *h, int id) {
node_t *p;
node_t *r = *h;
if (r && r->id == id) {
*h = r->next;
r->next = NULL;
return r;
}
p = list_find_before(h, id);
if (p) {
r = p->next;
p->next = r->next;
r->next = NULL;
return r;
}
return NULL; // no matching node
}

Related

hashtable issue in C; double free detected in tcache 2

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 */
}

Delete a prime number in a doubly linked list

#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *next;
struct node *prev;
}*head=NULL;
int length(struct node *p)
{
int len;
while(p!=NULL)
{
len++;
p = p->next;
}
return len;
}
void display(struct node *p)
{
if(p == NULL)
{
printf("Linked List is empty\n");
}
else
{
printf("Linked List: ");
while(p!=NULL)
{
printf("%d ", p->data);
p = p->next;
}
}
}
void insert(struct node *p, int index, int x)
{
struct node *t;
if(index == 0)
{
t = (struct node *)malloc(sizeof(struct node));
t->data = x;
t->next = head;
t->prev = NULL;
if(head != NULL)
{
head->prev = t;
}
head = t;
}
else
{
t = (struct node *)malloc(sizeof(struct node));
t->data = x;
for(int i=0; i<index-1; i++)
{
p = p->next;
}
t->prev = p;
t->next = p->next;
if(p->next != NULL)
{
p->next->prev = t;
}
p->next = t;
}
}
int checkprime(int n)
{
int prime = 1;
for(int i=2; i<n; i++)
{
if(n % 2 == 0)
{
prime = 0;
break;
}
}
if(prime == 0)
{
return 0; //It is not a prime number.
}
else
{
return 1; //It is a prime number.
}
}
void delete_prime_number(struct node *p)
{
struct node *q;
while(p != NULL)
{
q = p;
p = p->next;
if((checkprime(q->data)) == 1)
{
free(q);
}
}
}
int main()
{
insert(head, 0, 2);
insert(head, 1, 3);
insert(head, 2, 4);
insert(head, 3, 7);
insert(head, 4, 8);
insert(head, 5, 12);
insert(head, 6, 15);
insert(head, 7, 23);
display(head);
delete_prime_number(head);
display(head);
return 0;
}
This is the code I have tried for this. The problem is in the delete_prime_function. When I run it, it prints random values unlimited times.
I created a checkprime function which will return 1 if the number is prime and return 0 if the number is not prime.
Then in the delete_prime function, each time it would check the condition if((checkprime)==1), and if its true it would delete that node, and the process would go on until pointer "p" reaches NULL.
I'm not getting where I am doing it wrong.
EDIT:
Thank you, I implemented what #pmg and #VladfromMoscow pointed out. Here is the working code.
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *next;
struct node *prev;
};
int length(struct node *p)
{
int len = 0;
while (p != NULL)
{
len++;
p = p->next;
}
return len;
}
void display(struct node *p)
{
if (p == NULL)
{
printf("Linked List is empty\n");
}
else
{
printf("Linked List: ");
while (p != NULL)
{
printf("%d ", p->data);
p = p->next;
}
}
}
void insert(struct node **p, int index, int x)
{
struct node *t;
if (index == 0)
{
t = (struct node *)malloc(sizeof(struct node));
t->data = x;
t->next = *p;
t->prev = NULL;
if ((*p) != NULL)
{
(*p)->prev = t;
}
(*p) = t;
}
else
{
t = (struct node *)malloc(sizeof(struct node));
t->data = x;
for (int i = 0; i < index - 1; i++)
{
if((*p) == NULL)
{
printf("Linked List is empty!\n");
}
else
{
p = &(*p)->next;
}
}
t->prev = (*p);
t->next = (*p)->next;
if ((*p)->next != NULL)
{
(*p)->next->prev = t;
}
(*p)->next = t;
}
}
int checkprime(int n)
{
int prime = 1;
if(n == 0 || n == 1)
{
return 0;
}
else
{
for (int i = 2; i < n; i++)
{
if (n % i == 0)
{
prime = 0;
break;
}
}
if (prime == 0)
{
return 0; //It is not a prime number.
}
else
{
return 1; //It is a prime number.
}
}
}
void delete_prime_number(struct node **p)
{
while (*p != NULL)
{
if (checkprime((*p)->data) == 1)
{
struct node *q = *p;
if ((*p)->next != NULL)
{
(*p)->next->prev = (*p)->prev;
}
*p = (*p)->next;
free(q);
}
else
{
p = &(*p)->next;
}
}
}
int main()
{
struct node *head = NULL;
insert(&head, 0, 2);
insert(&head, 1, 3);
insert(&head, 2, 4);
insert(&head, 3, 7);
insert(&head, 4, 8);
insert(&head, 5, 12);
insert(&head, 6, 15);
insert(&head, 7, 23);
display(head);
delete_prime_number(&head);
printf("\n");
display(head);
return 0;
}
Thanks again :)
Imagine this 3 nodes list:
NULL==p /<==p /<==p
NODE NODE NODE
n==>/ n==>/ n==NULL
When you remove the 2nd node in this list you want to get
NULL==p /<==========p // changed prev link in 3rd node
NODE ---- NODE // deleted 2nd node
n==========>/ n==NULL // changed next link in 1st node
But your code is getting this
NULL==p ---- /<==p // prev links to deleted node
NODE ---- NODE
n==>/ ---- n==NULL // next links to deleted node
Beware the special cases of the first and last nodes in the list.
Your implementation of the list is incorrect and many functions can invoke undefined behavior.
For starters the functions shall not rely on the global variable head. In this case a program for example can not use two lists simultaneously.
The function length invokes undefined behavior because the local variable len is not initialized.
int length(struct node *p)
{
int len;
while(p!=NULL)
{
len++;
p = p->next;
}
return len;
}
You need to write
int len = 0;
In the function insert in this code snippet
for(int i=0; i<index-1; i++)
{
p = p->next;
}
t->prev = p;
t->next = p->next;
if(p->next != NULL)
{
p->next->prev = t;
}
p->next = t;
you do not check whether p is equal to NULL. For example if the list is empty that is head is a null pointer and the user specified index equal to 1 then p also will be a null pointer. So using it in expressions like for example this p->next invokes undefined behavior.
The function checkprime is also incorrect. It shows that numbers 0, 1 and all odd numbers are prime numbers due to the if statement
if(n % 2 == 0)
{
prime = 0;
break;
}
that will not get the control for such numbers.
So at first you have to write the list (declaring head as a local variable) and all the mentioned functions correctly before writing the function delete_prime_number which naturally also incorrect because at least it does not change the pointer head when the pointed node contains a prime number.
As for the function delete_prime_number itself then it can be defined the following wat
void delete_prime_number( struct node **head )
{
while ( *head != NULL )
{
if ( checkprime( ( *head )->data ) )
{
struct node *tmp = *head;
if ( ( *head )->next != NULL )
{
( *head )->next->prev = ( *head )->prev;
}
*head = ( *head )->next;
free( tmp );
}
else
{
head = &( *head )->next;
}
}
}
and can be called like
delete_prime_number( &head );

Trying to build a linked-list with strings as its entries

I'm trying to create a linked-list with strings as it data, and I have to do some opperations with them, but the opperations are cleared for integers only.
Those are the functions I've done the past weeks:
struct node {
int data;
char* s;
struct node* next;
};
typedef struct node node;
int remove_by_data(node** L, int data) {
if (*L == NULL) {
return 0;
}
node* p = *L;
if (p->data == data) {
*L = p->next;
free(p);
return 1;
}
else {
while (p->next != NULL && p->next->data != data) {
p = p->next;
}
if (p->next == NULL) {
return 0;
}
else {
node* q = p->next;
p->next = p->next->next;
free(q);
return 1;
}
}
}
node* search(node* L, int data) {
node* p = L;
while (p != NULL) {
if (p->data == data)
return p;
p = p->next;
}
return NULL;
}
int insert_end(node** L, int data) {
node* aux = malloc(sizeof(node));
if (!aux)
return 0;
aux->data = data;
aux->next = NULL;
node* p = *L;
if (p == NULL) {
*L = aux;
}
else {
while (p->next) {
p = p->next;
}
p->next = aux;
}
return 1;
}
int insert_begin(node** L, int data) {
node* aux = malloc(sizeof(node));
if (!aux)
return 0;
aux->data = data;
aux->next = *L;
*L = aux;
return 1;
}
void print_data(node* L) {
node* p = L;
while (p != NULL) { // while (p) {
printf("%d ",p->data);
p = p->next;
}
printf("\n");
}
int cont(node* L, int N){
int cont=1;
node* atual= L;
while (atual != search(L, N)){
cont++;
atual = atual->next;
}
return cont;
}
void swap_node(node** L, int m, int n){
int i, t;
node* p;
node* q;
p = q = *L;
for(i=1; i<m; i++)
p = p->next;
for(i=1; i<n; i++)
q = q->next;
t = p->data;
p->data = q->data;
q->data = t;
}
I just don't know how to "convert" those functions to strings, and how can I store a string into a list

double pointer to a node

My doubt is regarding pointer only,Here head is a double pointer to Queue if we are using *head than we are accessing the location(or address passed) inside main but when we are using simply head than we are using heading in the current function only which will hold the address of pointer to Queue now when we are doing this head=&(*head)->next the since (*head)->next is itself a address and when we use & before this ,than will a separate block will memory block will be created and hold the address of (*head)->next and we are assigning that address to head
I have this doubt because its like a two step process we cannot directly put the (*head)->next to sore something inside head we need to pass address of address for that we would require a extra block and when the loop will executed say n times than there will be n intermediate blocks?
Please tell me if i am correct or not
and tell the right logic thanks
void queue_push(Queue **head, int d, int p)
{
Queue *q = queue_new(d, p);
while (*head && (*head)->priority < p) {
head = &(*head)->next;
}
q->next = *head;
*head = q;
}
Full program is
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef struct Queue Queue;
struct Queue {
int data;
int priority;
Queue *next;
};
Queue *queue_new(int d, int p)
{
Queue *n = malloc(sizeof(*n));
n->data = d;
n->priority = p;
n->next = NULL;
return n;
}
int queue_pop(Queue **head)
{
assert(*head);
Queue *old = *head;
int res = old->data;
*head = (*head)->next;
free(old);
return res;
}
void queue_remove(Queue **head, int data)
{
while (*head && (*head)->data != data) {
head = &(*head)->next;
}
if (*head) queue_pop(head);
}
void queue_push(Queue **head, int d, int p)
{
Queue *q = queue_new(d, p);
while (*head && (*head)->priority < p) {
head = &(*head)->next;
}
q->next = *head;
*head = q;
}
int queue_empty(Queue *head)
{
return (head == NULL);
}
void queue_print(const Queue *q)
{
while (q) {
printf("%d[%d] ", q->data, q->priority);
q = q->next;
}
puts("$");
}
typedef struct Graph Graph;
typedef struct Edge Edge;
struct Edge {
int vertex;
int weight;
Edge *next;
};
struct Graph {
int v;
Edge **edge;
int *dist;
int *path;
};
Graph *graph_new(int v)
{
Graph *G = malloc(sizeof(*G));
G->v = v;
G->edge = calloc(v, sizeof(*G->edge));
G->dist = calloc(v, sizeof(*G->dist));
G->path = calloc(v, sizeof(*G->path));
return G;
}
void graph_delete(Graph *G)
{
if (G) {
for (int i = 0; i < G->v; i++) {
Edge *e = G->edge[i];
while (e) {
Edge *old = e;
e = e->next;
free(old);
}
}
free(G->edge);
free(G->dist);
free(G->path);
free(G);
}
}
Edge *edge_new(int vertex, int weight, Edge *next)
{
Edge *e = malloc(sizeof(*e));
e->vertex = vertex;
e->weight = weight;
e->next = next;
return e;
}
void graph_edge(Graph *G, int u, int v, int w)
{
G->edge[u] = edge_new(v, w, G->edge[u]);
G->edge[v] = edge_new(u, w, G->edge[v]);
}
void dijkstra(const Graph *G, int s)
{
Queue *queue = NULL;
for (int i = 0; i < G->v; i++) G->dist[i] = -1;
G->dist[s] = 0;
queue_push(&queue, s, 0);
while (!queue_empty(queue)) {
int v = queue_pop(&queue);
Edge *e = G->edge[v];
while (e) {
int w = e->vertex;
int d = G->dist[v] + e->weight;
if (G->dist[w] == -1) {
G->dist[w] = d;
G->path[w] = v;
queue_push(&queue, w, d);
}
if (G->dist[w] > d) {
G->dist[w] = d;
G->path[w] = v;
queue_remove(&queue, w);
queue_push(&queue, w, d);
}
e = e->next;
}
}
}
int main()
{
int t;
scanf("%d", &t);
while (t--) {
Graph *G;
int v, e, s;
scanf("%d %d", &v, &e);
G = graph_new(v);
for (int i = 0; i < e; i++) {
int u, v, w;
scanf("%d %d %d", &u, &v, &w);
graph_edge(G, u - 1, v - 1, w);
}
scanf("%d", &s);
dijkstra(G, s - 1);
for (int i = 0; i < G->v; i++) {
if (i != s - 1) {
printf("%d ", G->dist[i]);
}
}
puts("");
graph_delete(G);
}
return 0;
}
queue_push() fails to insert a new node correctly.
Only one node's .next is updated. Usually 2 nodes need their .next member updated. One in the original list (previous to the new node's location) and the new one.
I find creating a temporary node before the list, superhead, simplifies code.
void queue_push(Queue **head, int d, int p) {
Queue *q = queue_new(d, p);
Queue superhead; // Only superhead.next member important.
superhead.next = *head;
Queue *previous = &superhead;
while (previous->next && previous->next->priority < p) {
previous = previous->next;
}
q->next = previous->next;
previous->next = q;
*head = superhead.next;
}

Binary tree implementation C

The 't' pointer in the insert() function is set to NULL every time I call the insert function. Is it something to do with messing up of pointers?
int main() {
int num, i;
tree *t;
t = NULL;
for(i = 0; i < 5; i++) {
scanf("%d", &num);
insert(t, num);
}
//inorder(t);
return 0;
}
The insert function is as follows:
void insert(tree *t, int num) {
int flag;
tree *p, *q;
tree *temp = (tree *)malloc(sizeof(tree));
temp->data = num;
temp->left = NULL;
temp->right = NULL;
if(t == NULL) {
t = temp;
printf("Hello");
return;
}
printf("%d", t->data);
p = t;
while(p) {
q = p;
if(p->data <= num) {
p = p->right;
flag = 1;
}
else {
p = p->left;
flag = 0;
}
if(flag == 1)
q->right = temp;
else
q->left = temp;
}
}
My tree structure is as follows :
typedef struct tree {
int data;
struct tree *left, *right;
}tree;

Resources