Search code examples
cstructlinked-listsingly-linked-listfunction-definition

I have a problem with a problem that uses lists


I have a problem with this code. I have tried to debug with gdb and Valgrind, But nothing works...

The goal of the code is to create a list, where every string is added only if no existing node with the same string in already part of the list.

This is the code:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

struct node {
    char *word; 
    struct node *next; 
}; 

void print_list(struct node *head) {
    while ((head) != NULL) {
        printf(" %s -> ", head->word); 
        head = (head->next);    
    }
}

// insert a new node in head
void add_n(struct node **head, char *str) {
    struct node *new; 
    new = malloc(sizeof(struct node)); 
    if (new == NULL) {
        printf("Not enough memory\n");
        exit(EXIT_FAILURE);
    }
    new->word = str; 
    new->next = NULL; 
    if ((*head) == NULL){
        (*head) = new;      
    }
    while ((*head)->next != NULL) {
        head = &(*head)->next;
    }
    (*head)->next = new;
}

// check if str is present in the list 
int find_string(struct node **head, char *str) {
    int found = 0; 
    while ((*head) != NULL) {
        int i = strcmp(str, (*head)->word);     //i=0 are the same 
        if (i == 0) {
            found = 1; 
            return found;       
        }
        head = &((*head)->next); 
    }
    return found; 
}

// insert a new string in the list only if is new
void insert(struct node **head, char *str) {
    if (find_string(head, str) == 0) {
        add_n(head, str);
    }
}

void rem_ent(struct node **head, struct node *ent) {
    while ((*head) != ent) {
        head = &((*head)->next);
    }
    (*head) = ent->next; 
    
    free(ent); 
}

void fini_list(struct node **head) {
    while ((*head) != NULL) {
        rem_ent(head, *head); 
        head = &((*head)->next);    
    }
}

int main() {
    struct node *head = NULL; 

    insert(&head, "electric");
    print_list(head); 

    insert(&head, "calcolatori");
    print_list(head);

    insert(&head, "prova pratica");
    print_list(head);

    insert(&head, "calcolatori");
    print_list(head);
    fini_list(&head);
    //printf("lunghezza media = %f\n", avg_word_lenght(head)); 
    return 0; 
}

Maybe the error might be stupid, but I spent a lot of time debugging without success.


Solution

  • the function fini_list invokes undefined behavior due to the redundant statement

    head=&((*head)->next);  
    

    because the function rem_ent already set the new value of the pointer head.

    void rem_ent(struct node** head, struct node * ent){
        while((*head) != ent){
            head= &((*head)->next);
            }
        (*head)= ent->next; 
        
        free(ent); 
    }
    

    Remove the statement

    void fini_list(struct node** head){
        while((*head) != NULL){
            rem_ent(head, *head); 
            }
    }
    

    Also change the function add_n the following way

    // insert a new node in head
    void add_n(struct node ** head, char* str){
        struct node * new; 
        new = malloc(sizeof(struct node)); 
        if (new == NULL) {
            printf("Not enough memory\n");
            exit(EXIT_FAILURE);
            }
            new->word= str; 
            new->next = NULL; 
            if ((*head)==NULL){
                (*head)=new;    
            }
            else
            {
                while((*head)->next != NULL){
                    head = &(*head)->next;}
                (*head)->next = new;
            }
    }
    

    And next time format the code such a way that it would be readable.

    In general you should allocate dynamically memory for strings that will be stored in nodes of the list.