Search code examples
cstructsegmentation-faultscanf

Segmentation fault with the use of a structure while reading from a file


I have to read data from a .txt file, and then sort them.

I created my method on an other C file, and it worked perfectly, but when I import it, I got this Segmentation fault error.

I try each line of my program, and it seems that my problem is coming from these two functions :

ListScore* fillScore(){
    ListScore *list=malloc(sizeof(*list));
    FILE* f =NULL;
    int score;
    char name[20];
    f= fopen("score.txt", "r");
    if (f==NULL || list==NULL) {
        perror("fopen or list Null");
        exit(EXIT_FAILURE);
    }

    while(fscanf(f,"%d%s",&score,name)==2){
        insertElem(list,score,name);
    }
    fclose(f);
    bubbleSort(list);
    return list;
}

and

void bubbleSort(ListScore* list){
Score_s *get=list->first;
Score_s *move;
/* Checking for empty list */
if (list->first == NULL)
    {return;}

else{
    while(get->next!=NULL){
        move=list->first;
        while(move->next!=NULL){
            if(move->score<move->next->score){
                swap(move,move->next);
            }
            move=move->next;
            printTest();
        }
        get=get->next;
    }
}

}

and debugger show me this condition as the problem if(move->score<move->next->score); I can't understand why on an external C file, it worked, but in a complex project (with include.h) it doesn't work.

Thanks in advance.

EDIT : My struct ListScore is defined like this :

typedef struct ListScore{
    Score_s *first;    
}ListScore;

and Score_s like this

typedef struct Score_s Score_s;
struct Score_s{
    char name[20];
    int score;
    Score_s *next;
};

EDIT 2 : Here's the minimal example, but it works perfectly on it's own... as said in the beginning of this question;

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

typedef struct Score_s Score_s;

struct Score_s{
    char name[20];
    int score;
    Score_s *next;
};

typedef struct ListScore{
    Score_s *first;    
}ListScore;



void insertElem(ListScore* list,int s,char n[]){
    if(list==NULL){
        exit(EXIT_FAILURE);
    }
    Score_s* new;
    new=malloc(sizeof(*new));
    strcpy(new->name,n);
    new->score=s;
    new->next=list->first;
    list->first=new;
}

void swap(Score_s *a,Score_s *b){
    int tmp=a->score;
    a->score=b->score;
    b->score=tmp;
    char tmpS[20];
    strcpy(tmpS,a->name);
    strcpy(a->name,b->name);
    strcpy(b->name,tmpS);
}


void bubbleSort(ListScore* list){
    Score_s *get=list->first;
    Score_s *move;

    /* Checking for empty list */
    if (list->first == NULL)
        {return;}

    else{
        while(get->next!=NULL){
            move=list->first;
            while(move->next!=NULL){
                if(move->score<move->next->score){
                    swap(move,move->next);
                }
                move=move->next;
            }
            get=get->next;
        }
    }

}


void fillScore(){
    ListScore *list=malloc(sizeof(*list));
    FILE* f =NULL;
    int score;
    char name[20];
    f= fopen("score.txt", "r");
    if (f==NULL || list==NULL) {
        perror("fopen or list Null");
        exit(EXIT_FAILURE);
    }

    while(fscanf(f,"%s%19d",name,&score)==2){
        insertElem(list,score,name);
    }
    
    Score_s* new;
    new=malloc(sizeof(*new));
    new=list->first;
   
    fclose(f);
    printf("\n\n");
    bubbleSort(list);
    new=list->first;
    while(new!=NULL){
        printf("%s %d\n",new->name,new->score);
        new=new->next;
    }
    free(list);


}

int main(int argc, char const *argv[])
{
    fillScore();
    return 0;
}

Content of score.txt :

pat 20
ananna 20
radis 19
gg 121
nique 236
perie 125
aziz 127
telma 36
coc 1
aie 6
prout 236

and this is the output :

prout 236
nique 236
aziz 127
perie 125
gg 121
telma 36
ananna 20
pat 20
radis 19
aie 6
coc 1

Solution

  • In the function fillScore, you are not giving list->first any value, so that its value is indeterminate. Therefore, after adding elements to the linked list using the function insertElem, the last element of your linked list does not have a NULL pointer, but instead has a pointer with an indeterminate value. Eventually, the function bubbleSort will attempt to deference this indeterminate value, which is probably causing your segmentation fault.

    Therefore, you should set list->first to NULL.

    In your question, you posted two substantially different versions of the function fillScore. Since I do not know which one you are using, I cannot tell whether there are other issues in the code that you are using.

    Also, the line

    while(fscanf(f,"%s%19d",name,&score)==2){
    

    does not make sense. You probably intended to write

    while(fscanf(f,"%19s%d",name,&score)==2){
    

    instead.

    It is also worth noting that your program contains several memory leaks. You are freeing all the memory allocated by the line

    ListScore *list=malloc(sizeof(*list));
    

    but all the memory allocated by other calls to malloc in your program are not being freed. However, this is not the reason for the segmentation fault that you are having.

    After fixing all of the issues mentioned above, your code should look like this:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <stdbool.h>
    
    typedef struct Score_s Score_s;
    
    struct Score_s{
        char name[20];
        int score;
        Score_s *next;
    };
    
    typedef struct ListScore{
        Score_s *first;    
    }ListScore;
    
    void insertElem(ListScore* list,int s,char n[]){
        if(list==NULL){
            exit(EXIT_FAILURE);
        }
        Score_s* new;
        new=malloc(sizeof(*new));
        strcpy(new->name,n);
        new->score=s;
        new->next=list->first;
        list->first=new;
    }
    
    void swap(Score_s *a,Score_s *b){
        int tmp=a->score;
        a->score=b->score;
        b->score=tmp;
        char tmpS[20];
        strcpy(tmpS,a->name);
        strcpy(a->name,b->name);
        strcpy(b->name,tmpS);
    }
    
    
    void bubbleSort(ListScore* list){
        Score_s *get=list->first;
        Score_s *move;
    
        /* Checking for empty list */
        if (list->first == NULL)
            {return;}
    
        else{
            while(get->next!=NULL){
                move=list->first;
                while(move->next!=NULL){
                    if(move->score<move->next->score){
                        swap(move,move->next);
                    }
                    move=move->next;
                }
                get=get->next;
            }
        }
    
    }
    
    void fillScore(){
        ListScore *list=malloc(sizeof(*list));
        list->first = NULL;
        FILE* f =NULL;
        int score;
        char name[20];
        f= fopen("score.txt", "r");
        if (f==NULL || list==NULL) {
            perror("fopen or list Null");
            exit(EXIT_FAILURE);
        }
    
        while(fscanf(f,"%19s%d",name,&score)==2){
            insertElem(list,score,name);
        }
       
        fclose(f);
    
        bubbleSort(list);
    
        Score_s *new = list->first;
        while(new!=NULL){
            printf("%s %d\n",new->name,new->score);
    
            //remember pointer to previous node so that
            //it can be freed after use
            Score_s *prev = new;
    
            new=new->next;
    
            //free the pointer to the previous node
            free( prev );
        }
        free(list);
    }
    
    int main( void )
    {
        fillScore();
        return 0;
    }
    

    With the input specified in the question, this program has the following output:

    prout 236
    nique 236
    aziz 127
    perie 125
    gg 121
    telma 36
    ananna 20
    pat 20
    radis 19
    aie 6
    coc 1
    

    As you can see, all lines are correctly sorted by score.