Ошибка сегментации при чтении файла в C - PullRequest
2 голосов
/ 08 мая 2019

Я все еще очень плохо знаком с языком c и впервые играю с чтением файлов. У меня был подобный код к этому коду, который раньше работал отлично, но теперь я сталкиваюсь с проблемами. Я получаю сообщение об ошибке Segmentation fault (core dumped) каждый раз, когда пытаюсь запустить эту программу.

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

struct student {
    char first[30];
    char last[30];
    char ssn[9];
};

void make_arrays() {
    FILE *fp = fopen("students.db", "r");
    fseek(fp, 0, SEEK_END);
    long size = ftell(fp);
    fseek(fp, 0, SEEK_SET);

    long num_students = size / sizeof(struct student);
    printf("There are %ld students in the file", num_students);
    fclose(fp);
}

int main(int argc, char **argv[]) {
    make_arrays();
    return 0;
}

Ответы [ 2 ]

2 голосов
/ 08 мая 2019

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

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

Также обратите внимание, что еслифайл действительно двоичный, он должен быть открыт в двоичном режиме, чтобы избежать перевода конца строки:

FILE *fp = fopen("students.db", "rb");

Также измените прототип для main на int main(int argc, char *argv[]) или просто int main()char **argv[] слишком много звезд.

1 голос
/ 08 мая 2019

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

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

#include <sys/stat.h>

struct student /* Magic numbers everywhere */
{
    char first[30];
    char last[30];
    char ssn[9];

};




void* handle_nullptr_error (void* ptr, char *action, int code)
{
    if(ptr == NULL)
    {
        fprintf(stderr, "Failed to %s\n", action);

        exit(code);
    }

    printf("Succeeded to %s\n", action);

    return ptr;
}

int handle_nonzero_error (int val, char *action, int code)
{
    if(val != 0)
    {
        fprintf(stderr, "Failed to %s\n", action);

        exit(code);
    }

    printf("Succeeded to %s\n", action);

    return val;
}

int handle_negval_error (int val, char *action, int code)
{
    if(val < 0)
    {
        fprintf(stderr, "Failed to %s\n", action);

        exit(code);
    }

    printf("Succeeded to %s\n", action);

    return val;
}




/** This function is not guaranteed to be portable and work (but it will at least fail properly),
 * because not all systems and/or library implementations support `SEEK_END` in files
 * opened in text mode, as specified by @mode
 * Moreover, in binary mode it will behave in an undefined manner, because different systems
 * may store files data completely differently. In most cases it will succeed, just don't
 * write code that crashes if not.
 */
long int get_file_charcount (const char *filename, char* mode)
{
    FILE*       fp      = NULL;
    long int    fpSize  = 0L;

    /* Alignment for complicated function calls (for e.g where functions are passed as arguments) */
    fp = handle_nullptr_error       (fopen(filename, mode),     "open file.",           1);

    (void)handle_nonzero_error      (fseek(fp, 0, SEEK_END),    "seek end position.",   2);

    fpSize = handle_negval_error    (ftell(fp),                 "tell position.",       3);

    fclose(fp); /* - May fail, as well */

    return fpSize;
}

/** This function depends on POSIX headers and it is unix-conformant, although there are still
 * some exceptions.
 *
 * Note that the value returned is the length of the contents of the symbolic link,
 * and does not count any trailing null pads. The value is ought to be system-specific.
 */
_off64_t get_file_size (const char *filename)
{
    struct stat st = {0};

    (void)handle_negval_error(stat(filename, &st), "get file size.", (-1));

    return st.st_size;
}

/** A validation function should first determine whether file's size is
 * actually dividable by `sizeof(struct STUDENT_DESCRIPTION);`.
 *
 * Further more you can use `get_file_size()` as an alternative to
 * `get_file_charcount()`. In the latter case, make sure you to specify the
 * appropriate mode, "r" for text files and "rb" for binary files.
 */
void make_arrays ()
{
    long int    size            = get_file_charcount("myfile.txt", "r");
    long int    num_students    = size / sizeof(struct STUDENT_DESCRIPTION);

    printf("size of file: %ld\n", size);

    printf("There are %ld students in the file", num_students);
}




int main (void)
{
    make_arrays();

    return EXIT_SUCCESS;
}
...