Search code examples
cstringlinked-listsegmentation-faultstrcmp

Segmentation fault with strcmp in a list insertion


I'm trying to create a list in alphabetical order (first by author, then by name). I tried to do it by comparing the two strings with strcmp() but I'm getting a segmentation fault.

I'll leave the GDB run result down here and the function, it's one of the first programs I made with lists so the code has probably other errors.

GDB run :

Program received signal SIGSEGV, Segmentation fault.                         
0x0000000000400c65 in insert (lPtr=0x7fffffffeb38, isbn_i=978044,            
    name_i=0x7fffffffeb40 "Suzanne Collins",                                 
    author_i=0x7fffffffeb80 "The Hunger Games") at main.c:178                
178             while(strcmp(author_i, currPtr->author) < 0){
typedef struct library{ //struct insertion from stdin
    int isbn;
    char *author;
    char *name;
    int act; //actual books in memory
    int tot; //total books
    struct library *nextPtr; //node
}Lib;

typedef Lib *NodePtr;


//called by a while, receives input from integers and two arrays of char

void insert(NodePtr *lPtr, int isbn_i, char *name_i, char *author_i){  

    NodePtr newPtr = malloc(sizeof(Lib));

    newPtr->isbn = isbn_i;  //scanf insertion in node
    newPtr->author = author_i;
    newPtr->name = name_i;

    newPtr->nextPtr = NULL;
    NodePtr prevPtr = NULL;

    newPtr->act = 1;
    newPtr->tot = 1;

    if(lPtr == NULL){ //empty list
        *lPtr = newPtr;
        return;
    }

    NodePtr currPtr = *lPtr;

    while(strcmp(author_i, currPtr->author) < 0){ //author is different, list slides    
        prevPtr = currPtr;
        currPtr = currPtr->nextPtr;
    }

    if(strcmp(author_i, currPtr->author)== 0){ //same author

        while(strcmp(name_i, currPtr->name) < 0){ //list sliding
            prevPtr = currPtr;
            currPtr = currPtr->nextPtr;
        }

        if(strcmp(name_i, currPtr->name) == 0){ 
            currPtr->act += 1; //updates current counter and returns (to avoid duplicates)
            currPtr->tot += 1;

            free(newPtr);
            return;
        }
    }

    prevPtr->nextPtr = newPtr; //insertion between two nodes
    newPtr->nextPtr = currPtr;
}



Solution

  • in the following code :

        while(strcmp(author_i, currPtr->author) < 0){ //author is different, list slides    
            prevPtr = currPtr;
            currPtr = currPtr->nextPtr;
        }
    

    you do not check if currPtr->nextPtr is NULL (at the end of your list),
    if your list author only contains author that should be ordered after author_i you will reach the end without finding a place to insert.

    Example (unrelated field omitted for brievty):

    currPtr = {author:"Cressida Cowell", nextPtr=NULL};
    insert(lPtr = &currPtr, ...,author_i = "Suzanne Collins", ...);
    /// insertion location loop
    // while loop unrolled
    if("Suzanne Collins" > "Cressida Cowell") {
         prevPtr = currPtr ; // prevPtr = {author:"Cressida Cowell", nextPtr=NULL};
         currPtr = currPtr->nextPtr; // currPtr  = NULL
    }
    // next iteration
    if("Suzanne Collins"> NULL->author ) // de-referencing a NULL pointer, causing a Segmentation fault
    

    you could partially fix the code with the following fix:

        while(strcmp(author_i, currPtr->author) < 0){ //author is different, list slides    
            prevPtr = currPtr;
            currPtr = currPtr->nextPtr;
            if(currPtr == NULL) {break;} // exit loop if at end of the list
        }
    

    you still need to handle currPtr == NULL to avoid de-referencing the NULL pointer in currPtr when checking for title, my recommendation would be to combine the conditions in the insertion location searching loop.

        // implement a node comparison function
        int compareLib(NodePtr lib1, NodePtr lib2) {
            if((lib1 == NULL)||(lib2 == NULL)) return 0;
            int author_compare = strcmp(lib1->author, lib2->author);
            if (author_compare != 0) return author_compare;
            return strcmp(lib1->name, lib2->name);
        }
        ...
        while(compareLib(newPtr, currPtr)){ 
            prevPtr = currPtr;
            currPtr = currPtr->nextPtr;
            if(currPtr == NULL) {break;} // exit loop if at end of the list
        }
    

    You still need to Handle currPtr == NULL when adding the new list node