在C中读取文件时出现分段错误

时间:2019-05-07 21:36:59

标签: c segmentation-fault

我对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 个答案:

答案 0 :(得分:2)

分段错误可能是由于fopen无法打开文件引起的。

您应始终测试此类故障并通过提示信息退出。

还请注意,如果文件确实是二进制文件,则应以二进制模式打开它,以避免换行符转换:

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

也将main的原型更改为int main(int argc, char *argv[])或简单地更改为int main()char **argv[]中的星星过多。

答案 1 :(得分:1)

您不必将我的答案标记为已接受,只想激发人们编写代码,使其可读性和安全性。在质量是一个重要因素的情况下,不要懒于编写这样的代码。

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