Можете ли вы помочь мне понять, почему я получаю эти ошибки сегментации?

Я пытаюсь создать эту небольшую базу данных студентов, используя связанные списки в C. По какой-то причине я получаю ошибку сегментации при втором запуске этой функции. У меня есть переключатель внутри цикла while, где я могу запускать различные функции, вводя число с клавиатуры. Итак, когда я запускаю программу, нажмите 1, чтобы запустить эту функцию ниже, все работает нормально. Но когда я пытаюсь запустить его во второй раз, не прерывая программу между ними, происходит сбой, и отладчик сообщает мне, что произошла ошибка сегментации. Я не могу понять, почему.

Это функция в моем скрипте.

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++;

}

Я просто хочу, чтобы функция могла работать неограниченное количество раз без сбоев.

Когда я запускаю функцию в первый раз, current_student имеет ожидаемый адрес памяти, а current_student->next_student имеет значение NULL, как и ожидалось. Второй раз текущий студент имеет тот же адрес, а current_student->next_student имеет адрес, так что пока все работает?

Current_student, student head, current_study и Study_head объявлены как глобальные указатели.

Обновлено: вот объявления структур и указатели на выделенную память. Они находятся вне main на верхнем уровне вне любой функции:

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;

Отредактируйте свой пост, чтобы оставить немного меньше воображению. Каковы ваши struct определения? Отредактируйте, чтобы создать минимальный воспроизводимый пример

ryyker 27.12.2022 15:21

Вам не хватает кода. Мы не знаем, какого типа ваши переменные, такие как current_student.

Robert Harvey 27.12.2022 15:22

Первое, что нужно сделать, это выяснить, какая строка кода, в частности, вызывает сбой. С помощью этой информации вы будете знать, какой разыменование указателя является виновником и, следовательно, какая переменная установлена ​​неправильно, и вы можете вернуться оттуда к основной причине ошибки.

Jeremy Friesner 27.12.2022 15:29

Так как функция всегда возвращает 1, потому что study_head равно NULL. (Не нужно тестировать дважды: if (current_study == NULL || current_study == NULL))

CGi03 27.12.2022 16:13

У вас как минимум 7 глобальных переменных слишком много.

n. m. 27.12.2022 20:35

Вы никогда не должны приводить возвращаемое значение malloc в программе C. Это блокирует важные сообщения об ошибках.

n. m. 27.12.2022 21:20
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
6
85
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Не видя содержимого вашей основной функции и того, как вызывалась функция add_student, я взял немного художественной лицензии на рефакторинг некоторых функций, чтобы они чувствовали, когда добавляется первая структура студента или структура обучения, и действовали соответственно. обеспечить правильную начальную точку и последующую цепочку связанных списков. Ниже приведена версия вашей функции с некоторыми изменениями для определения начальной точки студента/учебы, а также основная функция, которая позволяет вводить непрерывное количество записей студентов и учебы. Это немного длинно, но я не мог понять, как сжать это дальше.

#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;
}

Некоторые моменты, на которые следует обратить внимание.

  • Вместо немедленной проверки значения указателя в структурах student_head и study_head и выхода эта информация используется для определения того, предназначен ли вызов этой функции для установки исходных структур student и study в связанном списке.
  • Как было отмечено в комментариях, приведение функции malloc было удалено.
  • Чтобы обеспечить целостность указателя связанного списка, указатели следующего студента и следующего исследования устанавливаются в NULL для каждого вновь созданного студента и структуры обучения.
  • Переменная ответа была добавлена, чтобы обеспечить очень простой способ указания того, что ввод данных о студенте и учебе выполнен; что-то более сложное может быть использовано для определения завершения ввода данных.
  • В качестве доказательства функционирования введенные данные о студентах и ​​учебе распечатываются в основной функции.

Ниже приведен пример вывода терминала для двух записей студента/учебы; однако можно было бы ввести больше студентов и связанных с ними учебных структур.

@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

Кроме того, вы можете изучить возможность передачи вашей структуры или адреса структуры в качестве параметров функции вместо использования глобальных переменных, как указано в комментариях. Но для того, чтобы предоставить своевременный ответ с кодом как есть, я оставил ваши переменные как глобальные переменные.

Попробуйте и посмотрите, соответствует ли это духу вашего проекта.

Другие вопросы по теме