Ошибка сегментации при чтении файла структуры - PullRequest
0 голосов
/ 06 октября 2019

Я пытаюсь получить доступ к файлу и прочитать его, используя fread () в программе, управляемой из меню. Я понятия не имею, какая часть кода вызывает ошибку сегментации. Все, что я получил от вызова функции чтения, это ошибка сегментации (ядро сброшено) и буквальный выход из интерфейса.

Исходный код:

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

#define MAX_SIZE 100

struct student {
    char registration[MAX_SIZE], location[MAX_SIZE], faculty[MAX_SIZE];
        int yearOfBirth, monthOfBirth, dayOfBirth, layerArch1, layerArch2, levelOfStudy, graduatingYear;    
};

int writeInfo(FILE **resident, FILE **transient, const char *file1, const char *file2, struct student *res, struct student *tra);
int readTransient(FILE **transient, const char *file2, struct student *tra);
int display(FILE **resident, const char *file1, struct student *res);

/**************************************************************/

int main (int argc, char **argv) {

    char file1[MAX_SIZE], file2[MAX_SIZE];

    FILE *resident = (FILE*) malloc(sizeof(FILE));
        FILE *transient = (FILE*) malloc(sizeof(FILE));

    struct student *res = (struct student *) malloc(sizeof(struct student));
    struct student *tra = (struct student *) malloc(sizeof(struct student));

    int choice = 0;

    while (choice >= 0 && choice <= 3) {
        printf("\n\tPlease enter the following choice\n\n");
        printf("*****************************************************\n");
        printf("\t\t1: Add Information\n");
        printf("\t\t2: Read Information\n");
        printf("\t\t3: Display Information\n");
        printf("\t\t0: Exit\n");
        printf("*****************************************************\n");

        printf("\nEnter a number: ");
        scanf("%d", &choice);

        switch (choice) {
            case 0:
                exit(1);
            case 1:
                printf("\nEnter name of the first file\n");
                scanf("%s", file1);

                printf("\nEnter name of the second file\n");
                scanf("%s", file2);
                writeInfo(&resident, &transient, file1, file2, res, tra);
                break;
            case 2: 
                printf("\nEnter name of the file\n");
                scanf("%s", file2);
                readTransient(&transient, file2, tra);
                break;
            case 3: 
                printf("\nEnter name of the file\n");
                scanf("%s", file1);
                display(&resident, file1, res);
                break;
            default:
                printf("Wrong choice. Enter again!\n\n");
                break;
        }
    }

    return 0;
}
int writeInfo(FILE **resident, FILE **transient, const char *file1, const char *file2, struct student *res, struct student *tra) {

        *resident = fopen(file1, "w");
        *transient = fopen(file2, "w"); 

        if (*resident == NULL) {
            fprintf(stderr, "\nError open file\n");
            exit(1);
        }

        if (*transient == NULL) {
            fprintf(stderr, "\nError open file\n");
            exit(1);
        }

        printf("Enter a registration number [7 digits]: ");
            scanf("%s", res->registration);

            printf("Enter location (location in currency, AUS CND SIN): ");
            scanf("%s", res->location);
            strcpy(tra->location, res->location);

            printf("Enter faculty (ENG BUS SCI MED): ");
            scanf("%s", res->faculty);
        strcpy(tra->faculty, res->faculty);

            printf("Enter birth of year (19XX 200X): ");
            scanf("%d", &res->yearOfBirth);

            printf("Enter birth of month (XX): ");
            scanf("%d", &res->monthOfBirth);
        tra->monthOfBirth = res->monthOfBirth;

            printf("Enter birth of date (XX): ");
            scanf("%d", &res->dayOfBirth);
        tra->dayOfBirth = res->dayOfBirth;

            printf("Enter level of study (1 -first, 2- second, 3- third, 4-fourth, 5 - other): ");
            scanf("%d", &res->levelOfStudy);
        tra->levelOfStudy = res->levelOfStudy;

            printf("Enter graduating year (XXXX): ");
            scanf("%d",&res->graduatingYear);
        tra->graduatingYear = res->graduatingYear;

            printf("Enter layer of Architecture 1 (0-sensing, 1-network, 2-smart(hidden), 3-devices): ");
            scanf("%d",&res->layerArch1);

            printf("Enter layer of Architecture 2 (0-sensing, 1-network, 2-smart(hidden), 3-devices): ");
            scanf("%d", &res->layerArch2);
        tra->layerArch2 = res->layerArch2;

        //write entire sturcture to Student file
        fwrite(&res, sizeof(struct student), 1, *resident);

        fwrite(&tra, sizeof(struct student), 1, *transient);

        fclose(*resident);
        fclose(*transient);
}

int display(FILE **resident, const char *file1, struct student *res) {

    *resident = fopen(file1, "r");

    if (*resident == NULL) {
        fprintf(stderr, "\nError opening file!\n\n");
        exit(1);
    }

    while(fread(&res, sizeof(struct student), 1, *resident) != EOF) {
        printf("%d%s%d%d%d%d%d%s%d%s%d%d\n\n", res->yearOfBirth, res->registration, res->monthOfBirth, res->dayOfBirth, res->layerArch1, res->layerArch2, res->levelOfStudy, res->location, res->graduatingYear, res->faculty, res->dayOfBirth, res->monthOfBirth);
    }

    fclose(*resident);
}

int readTransient(FILE **transient, const char *file2, struct student *tra) {

    *transient = fopen(file2, "r");

    if (*transient == NULL) {
        fprintf(stderr, "\nError opening file!\n\n");
        exit(1);
    }

    while(fread(&tra, sizeof(struct student), 1, *transient) != EOF) {
        printf("%d%d%s%d%s%d%d\n\n", tra->layerArch2, tra->levelOfStudy, tra->location, tra->graduatingYear, tra->faculty, tra->dayOfBirth, tra->monthOfBirth);
    }

    fclose(*transient);
}

Вы можете попробоватьПриведенная выше программа, хотя она прекрасно работает только для добавления информации, а не для чтения и отображения.

Вывод:

Enter name of the file
l.txt
Segmentation fault (core dumped)

Спасибо за вашу любезную помощь и разъяснения. С благодарностью.

1 Ответ

1 голос
/ 06 октября 2019

Каждый раз, когда вы отлаживаете проблему с памятью (или, в действительности, просто когда вы делаете отладочную сборку), вы должны компилировать с -g -fsanitize=address, если вы используете GCC или clang. Дезинфицирующее средство адреса будет печатать точно там, где ваш код обращается к памяти, которой он не должен, независимо от того, была ли эта память недавно освобождена или находится после конца выделенного блока или является просто диким указателем и т. Д.

Вы делаетеFILE *f = malloc(sizeof(FILE)) - это излишне. fopen вернет FILE*, поэтому, когда вы делаете f = fopen(...), ваша программа просто игнорирует существующее значение в f и перезаписывает его указателем, возвращенным fopen. Это не вызывает вашего segfault.

В циклах, где вы читаете файлы, вы делаете while (fread(...) != EOF). fread не возвращает EOF, когда он достиг конца файла;он просто вернет число, которое меньше запрашиваемого вами числа, и затем вы сможете проверить, было ли это из-за ошибки или EOF с функциями ferror и feof. Фактически, fread не мог вернуть EOF, даже если бы захотел;EOF обычно равен -1, а fread возвращает size_t без знака. Это также не должно вызывать вашего segfault, оно должно просто закончить печатью последнего элемента в бесконечном цикле, потому что fread просто не коснется вашей структуры и вернет 0 навсегда, когда достигнет конца файла.

Ваш сегмент: Вы делаете fread(&res, sizeof(struct student), 1, *resident). res уже указатель (struct student *res), поэтому, когда вы делаете &res, вы получаете указатель на ваш указатель. fread заполняет все, на что указывает, то есть заполнит ваш указатель на ученика, не заполнит вашего ученика. Указатель намного меньше, чем ваша большая структура студента, поэтому он в конечном итоге записывает после конца и начинает записывать в случайную память стека, что нехорошо. Если вы замените этот &res на res, он больше не будет зависать.

...