Home > Software engineering >  segmentation fault for a bool function that's adds students to a linked list
segmentation fault for a bool function that's adds students to a linked list

Time:08-10

my assignment is to create a linked list and then write a bool function attempts to add a student with given id and name into the given list; if a student with that id is already in the list then return false, otherwise the list is modified and true is returned. Im a beginner and I rarely understand why segmentation faults occur so any help will be appreciated.

here are my structure definitions(provided by prof)

struct snode{
  int id;
  char * name;
  struct snode * next;
};

struct slist{
 struct snode * front;
};

here is my bool function

bool insert_student(int id, char name[], struct slist * lst) {
    struct snode *head = malloc(sizeof(struct snode));
    head = lst->front;
    // check if list is empty
    if (head != NULL) {
        struct snode *node = malloc(sizeof(struct snode));
        while (node != NULL) {
            // traverse the list to see if student exists in list
            if (node->id = id) {
                return 0;
            }
            else {
                // if it doesnt exist, add it
                struct snode *ins_std = malloc(sizeof(struct snode));
                ins_std = node->next;
                ins_std->id = id;
                ins_std->name = name;
                ins_std->next = lst->front;
                lst->front = ins_std;
                 
                return 1;    
            }
                 
            node = node->next;    
        } 
     } // if list is empty
     else {
         head->next = NULL;
         head->name = name;
         head->id = id;
         return 1;
     }
}

main function

int main() {
    struct slist *head = create_list();
    int id1 = 11001;
    int id2 = 11002;
    int id3 = 11003;
    int id4 = 11004;
    int id5 = 11005;
    char name1[] = "Dave";
    char name2[] = "Ali";
    char name3[] = "John";
    char name4[] = "Randall";
    char name5[] = "Kelly";

    assert(insert_student(id1, name1, head) == 1);
    insert_student(id2, name2, head);
    insert_student(id3, name3, head);
    insert_student(id4, name4, head);
    insert_student(id5, name5, head);
}

CodePudding user response:

Im a beginner and I rarely understand why segmentation faults occur I suspect you never do at this stage.

  struct snode *head = malloc(sizeof(struct snode));
  head = lst->front;

Here you allocated some space and save the reference to head, only to be overwritten by lst->front (which could be NULL). These two lines already cause segfault. I think what you are trying to do is to save the reference to the allocated space to lst->front, namely lst->front = head; instead of the other way around.

if(node->id = id){

Common error, use == for equality check.

struct snode *ins_std =malloc(sizeof(struct snode));
ins_std = node->next;

Similar issue to the first code snippet.

Solving the above issues should fix the segfaults and assertion errors. There are also a few logical loopholes in the code, but that is for another story.

CodePudding user response:

As a beginner, it helps to have "working code" to study. Here's a 'stripped down' version of your assignment. Make sure you understand what it does, then gradually add elaborations to build-up toward the entire project.

Programs aren't "typed-in", straight from brain to keyboard. You start off with something simple, then SLOWLY embellish that. Compile (with warnings turned up to the max) often, and test each step along the way.

Best wishes.

struct snode{
    int id;
    struct snode * next;
};

bool addNode( struct snode **pList, int id ) {
    for( struct snode *pSrch = *pList; pSrch; pSrch = pSrch->next )
        if( pSrch->id == id )
            return false; // already on list...

    struct snode *pNew = malloc( sizeof( *pNew ) );
    // check of malloc() success omitted

    pNew->id = id;
    pNew->next = *pList; // PREpending to existing list
    *pList = pNew;

    return true;
}

int main() {
    int ids[] = { 11001, 11002, 11003, 11004, 11005, 11002, 11006, 11007, }; // Notice blooper
    const int nIDs = sizeof ids/sizeof ids[0];
    struct snode *pList = NULL; // This will be 'buried' as "front"...

    for( int i = 0; i < nIDs; i   ) {
        printf( "ID %d ... ", ids[i] );
        if( addNode( &pList, ids[i] ) )
            printf( "Success\n" );
        else
            printf( "Failed\n" );
    }

    for( struct snode *pWalk = pList; pWalk; pWalk = pWalk->next )
        printf( "Walking... ID %d\n", pWalk->id );

    return 0;
}

CodePudding user response:

There are several mistakes in the code shown.

Here is a cleaned up example.

Within insert_student we:

  1. Immediately check that lst is not NULL. If it is, we immediately return false. Every point in the function afterward we can assume lst is not NULL.
  2. Create a pointer to a node that will point to the last node in the list.
  3. If the front node in the list is not NULL we proceed to check if the node is the last. If it is, store a pointer to it in last. And if the id is already taken, we immediately return false.
  4. Now we allocate a new node, making sure to allocate space for the name (and the null terminator character), and using strcpy to copy the name argument into the memory we've just allocated.
  5. If last was assigned something other than NULL, have its next pointer point to the new node.
  6. If last is still NULL it stands to reason lst->front was NULL. Assign the new node pointer to that pointer.
  7. If execution has reached this point, the insertion has happened. Return true.

A further exercise would be to write a function to free the allocated memory.

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

struct snode {
    int id;
    char *name;
    struct snode *next;
};

struct slist {
    struct snode *front;
};

bool insert_student(struct slist *lst, int id, const char *name);

int main() {
    struct slist *lst = malloc(sizeof(struct slist));

    insert_student(lst, 1, "Bob");
    insert_student(lst, 2, "Dave");

    for (struct snode *cur = lst->front; cur; cur = cur->next) {
        printf("-, %s\n", cur->id, cur->name);
    }

    return 0;
}

bool insert_student(struct slist *lst, int id, const char *name) {
    if (!lst) return 0;

    struct snode *last = NULL;

    if (lst->front) {
        for (struct snode *cur = lst->front; cur; cur = cur->next) {
            if (cur->next == NULL) last = cur;
            if (cur->id == id) return 0;
        }
    }

    struct snode *new_node = malloc(sizeof(struct snode));
    new_node->id = id;
    new_node->name = malloc(strlen(name)   1);
    strcpy(new_node->name, name);

    if (last) {
        last->next = new_node;
    }
    else {
        lst->front = new_node;
    }

    return 1;
}

Output:

 1, Bob
 2, Dave
  • Related