Home > Net >  Can you help me understand why I am getting these segmentation faults?
Can you help me understand why I am getting these segmentation faults?

Time:12-28

I am trying to build this little database of students, using linked lists in C. For some reason I am getting a segmentation fault the second time I run this function. I have a switch inside a while loop where I can run the different functions by entering a number from the keyboard. So when I start the program, press 1 to run this function below, everything works fine. But when I try to run it a second time without terminating the program in between, it crashes and the debugger tells me that there was a segmentation fault. I can't figure out why.

This is a function in my script.

int add_student(void){

    current_student = student_head;
    current_study = study_head;

    if (current_study == NULL || current_study == NULL)
        return 1;


    while(current_student->next_student != NULL){
        current_student = current_student->next_student;
    }


    current_student->next_student = (student*)malloc(sizeof(student));

    
    printf("Enter the persons personal number.");
    scanf("%d", &current_student->next_student->pernum);

    printf("Enter the persons name");
    scanf("%s", current_student->next_student->name);

    printf("Male or female? Write 1 for male and 0 for female.");
    scanf("%d", &current_student->next_student->is_male);
        if(current_student->next_student->is_male == 0)
            num_of_female  ;
        else
            num_of_male  ;
            

    printf("Enter the persons age");
    scanf("%d", &current_student->next_student->age);

    printf("Enter the persons email");
    scanf("%s", current_student->next_student->email);

    while(current_study->next_study != NULL){
        current_study = current_study->next_study;
    }

    current_study->next_study = (study*)malloc(sizeof(study));

    current_study->next_study->pernum = current_student->next_student->pernum;

    printf("Does this student study math? Asnwer 1 for yes or 0 for no.");   // Field of study.
    scanf("%d", &current_study->next_study->math);

    printf("Does this student study english? Asnwer 1 for yes or 0 for no.");
    scanf("%d", &current_study->next_study->english);

    printf("Does this student study chemistry? Asnwer 1 for yes or 0 for no.");
    scanf("%d", &current_study->next_study->chemistry);

    printf("Does this student study biology? Asnwer 1 for yes or 0 for no.");
    scanf("%d", &current_study->next_study->biology);

    printf("Does this student study history? Asnwer 1 for yes or 0 for no.");
    scanf("%d", &current_study->next_study->history);

    num_of_stud  ;

}

I just want the function to be able to run an indefinite amount of times without crashing.

When I run the function the first time, current_student has a memory address as expected and current_student->next_student is NULL as expected. The second time current student has the same address and current_student->next_student has an address, so everything seems to be working so far?

Current_student, student head, current_study and study_head are all declared as global pointers.

Edit: Here are the declarations to the structs and the pointers to allocated memory. These are outside main on the top level outside any function:

typedef struct student{
int pernum;
char name[100];
int is_male;
int age;
char email[100];
struct student *next_student;
}student;

typedef struct study{
int pernum;
int math;
int english;
int chemistry;
int biology;
int history;
struct study *next_study;
}study;

int num_of_stud = 0;
int num_of_female = 0;
int num_of_male = 0;

student *current_student;
study *current_study;

student *student_head = NULL;
study *study_head = NULL;

CodePudding user response:

Without seeing the content of your main function and how the add_student function was being called, I took a bit of artistic license to refactor some of the function so that it would sense when the first student structure or study structure was being added and act accordingly to provide a proper starting point and subsequent linked list chain. Following is a version of your function with some tweaks to determine a starting student/study point along with a main function that allows for a continuous number of student and study records to be entered. It is a bit lengthy, but I could not figure how to condense this any further.

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

typedef struct student
{
    int pernum;
    char name[100];
    int is_male;
    int age;
    char email[100];
    struct student *next_student;
} student;

typedef struct study
{
    int pernum;
    int math;
    int english;
    int chemistry;
    int biology;
    int history;
    struct study *next_study;
} study;

int num_of_stud = 0;
int num_of_female = 0;
int num_of_male = 0;

student *current_student = NULL;
study *current_study = NULL;

student *student_head = NULL;
study *study_head = NULL;

int add_student(void)
{
    int resp = 0;                                           /* Added to provide a user controlled end to student and study data entry */

    if (current_student == NULL)                            /* If this is the initial student set up the initial structure allocation */
    {
        current_student = malloc(sizeof(student));
        student_head = current_student;
    }
    else                                                    /* Else, chase down the linked list to the last current student */
    {
        while(current_student->next_student != NULL)
        {
            current_student = current_student->next_student;
        }
    }

    current_student->next_student = malloc(sizeof(student));

    printf("Enter the person's personal number: ");
    scanf("%d", &current_student->next_student->pernum);

    printf("Enter the persons name: ");
    scanf("%s", current_student->next_student->name);

    printf("Male or female? Write 1 for male and 0 for female: ");
    scanf("%d", &current_student->next_student->is_male);
    if(current_student->next_student->is_male == 0)
        num_of_female  ;
    else
        num_of_male  ;

    printf("Enter the persons age ");
    scanf("%d", &current_student->next_student->age);

    printf("Enter the persons email ");
    scanf("%s", current_student->next_student->email);

    current_student->next_student->next_student = NULL;     /* Make sure the last student element has its pointer properly initialized */

    if (current_study == NULL)                              /* If this is the initial study element set up the initial structure allocation */
    {
        current_study = malloc(sizeof(study));
        study_head = current_study;
    }
    else                                                    /* Else, chase down the linked list to the last current study element */
    {
        while(current_study->next_study != NULL)
        {
            current_study = current_study->next_study;
        }
    }

    current_study->next_study = malloc(sizeof(study));

    current_study->next_study->pernum = current_student->next_student->pernum;

    printf("Does this student study math? Asnwer 1 for yes or 0 for no: ");   // Field of study.
    scanf("%d", &current_study->next_study->math);

    printf("Does this student study english? Asnwer 1 for yes or 0 for no: ");
    scanf("%d", &current_study->next_study->english);

    printf("Does this student study chemistry? Asnwer 1 for yes or 0 for no: ");
    scanf("%d", &current_study->next_study->chemistry);

    printf("Does this student study biology? Asnwer 1 for yes or 0 for no: ");
    scanf("%d", &current_study->next_study->biology);

    printf("Does this student study history? Asnwer 1 for yes or 0 for no: ");
    scanf("%d", &current_study->next_study->history);

    current_study->next_study->next_study = NULL;           /* Make sure the last study element has its pointer properly initialized */

    num_of_stud  ;

    printf("More students 0/1 ");                           /* Send a response back to the main function to determine if further entry will occur */
    scanf("%d", &resp);

    if (resp == 0)
    {
        return -1;
    }

    return 0;
}

int main()
{
    while (1)                                               /* A test harness to allow a variable number of students to be entered */
    {
        if (add_student() == -1)
        {
            break;
        }
    }

    current_student = student_head->next_student;           /* This bit added just to verify what was entered */

    printf("Student list\n-----------------------------------------\n");

    while (1)
    {
        printf("Number: %d  Name: %s\n", current_student->pernum, current_student->name);

        if (current_student->next_student == NULL)
        {
            break;
        }
        current_student = current_student->next_student;
    }

        current_student = student_head->next_student;

    printf("\nStudy list\n-----------------------------------------\n");

    while (1)
    {
        printf("Person number: %d  Math: %d  English: %d  Chemistry: %d  Biology: %d  History: %d\n", current_study->pernum, current_study->math, current_study->english, current_study->chemistry, current_study->biology, current_study->history);

        if (current_study->next_study == NULL)
        {
            break;
        }
        current_study = current_study->next_study;
    }

    return 0;
}

Some points to note.

  • Instead of immediately testing the pointer value in the student_head and study_head structure and exiting, that information is used to determine if the call to this function is meant to set up the initial student and study structures in the linked list.
  • As noted in the comments, the casting of the malloc function was removed.
  • To insure the linked list pointer integrity, the next student and next study pointers are set to NULL for every newly created student and study structure.
  • A response variable was added to provide a very simple method for indicating that student and study data entry is done; something more sophisticated might be used to determine when data entry is complete.
  • Just as a proof of function, the entered student and study records are printed out in the main function.

Following is some sample terminal output for two student/study entries; however, more students and their associated study structures could have been entered.

@Vera:~/C_Programs/Console/StudentBody/bin/Release$ ./StudentBody 
Enter the person's personal number: 22
Enter the persons name: Craig
Male or female? Write 1 for male and 0 for female: 1
Enter the persons age 18
Enter the persons email [email protected]
Does this student study math? Asnwer 1 for yes or 0 for no: 1
Does this student study english? Asnwer 1 for yes or 0 for no: 0
Does this student study chemistry? Asnwer 1 for yes or 0 for no: 0
Does this student study biology? Asnwer 1 for yes or 0 for no: 0
Does this student study history? Asnwer 1 for yes or 0 for no: 0
More students 0/1 1
Enter the person's personal number: 33
Enter the persons name: Lily
Male or female? Write 1 for male and 0 for female: 0
Enter the persons age 19
Enter the persons email [email protected]
Does this student study math? Asnwer 1 for yes or 0 for no: 0
Does this student study english? Asnwer 1 for yes or 0 for no: 1
Does this student study chemistry? Asnwer 1 for yes or 0 for no: 0
Does this student study biology? Asnwer 1 for yes or 0 for no: 0
Does this student study history? Asnwer 1 for yes or 0 for no: 0
More students 0/1 0
Student list
-----------------------------------------
Number: 22  Name: Craig
Number: 33  Name: Lily

Study list
-----------------------------------------
Person number: 22  Math: 1  English: 0  Chemistry: 0  Biology: 0  History: 0
Person number: 33  Math: 0  English: 1  Chemistry: 0  Biology: 0  History: 0

Also, you may want to explore passing your structure or structure address as function parameters in lieu of using global variables as noted in the comments. But in order to provide a timely response with the code as is, I left your variables as global variables.

Give that a try and see if it meets the spirit of your project.

  • Related