C - 程序为SEGFAULT提供了for循环,但并非没有

时间:2018-06-14 20:14:50

标签: c segmentation-fault

我正在做一个读取3x3矩阵的程序。

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

typedef struct { 
    int row;
    int col;
    long **tab;
} matr;

int SIZE = 3;

void *emalloc(size_t size) {
    void *memory = malloc(size);

    if (!memory) {
        fprintf(stderr, "ERROR: Failed to malloc.\n");
        exit(1);
    }

    return memory;
}

void file_to_matrix(FILE *path_matr, matr *m) {
    long **matrix = (long**) emalloc(SIZE * sizeof(long*));
    for (int i = 0; i < SIZE; i++) matrix[i] = (long*) emalloc(SIZE * sizeof(long));

    char line[4];
    fscanf(path_matr, " %[^\n]", line);

    // This code does not give SEGFAULT
    // for (int i = 0; i < SIZE; i++) {
    //  fscanf(path_matr, "%ld%ld%ld", &matrix[i][0], &matrix[i][1], &matrix[i][2]);
    // }

    // The code below gives SEGFAULT
    for (int i = 0; i < SIZE; i++) {
        for (int j = 0; j < SIZE; j++) {
            fscanf(path_matr, "%ld", &matrix[i][j]);
        }
    }

    m->row = SIZE;
    m->col = SIZE;
    m->tab = matrix;
}

int main(int args, char *argv[]) {
    FILE *path_matr = fopen(argv[1], "r");

    /*Getting the matrices*/
    int n_matr; // Number of matrices
    fscanf(path_matr, "%d", &n_matr);
    matr *matrices = emalloc(n_matr * sizeof(matr));

    for (int i = 0; i < n_matr; i++) {
        file_to_matrix(path_matr, &matrices[i]);
    }

    for (int i = 0; i < n_matr; i++)
        free(matrices[i].tab);
    free(matrices);
    fclose(path_matr);

    return 0;
}

请注意file_to_matrix函数中有两个for循环。一个版本给出了分段错误,另一个版本没有。为什么?有趣的是:如果我启用-O2,两个版本都可以。

使用gcc -std = c11 test.c编译-o test -g&amp;&amp; ./test in.txt(gcc version 4.9.2)。

in.txt:

3
∗∗∗
11 12 1444
21 22 23
31 32 33
∗∗∗
11 12 13
21 22 23
31 32 33
∗∗∗
11 12 13
21 22 23
31 31 33
∗∗∗

P.S。:我在这里发布的代码是另一个代码的一部分,为了简单起见,我从中移除了一些块(例如检查参数的数量,fopen&#39; s返回等)。我在这里描述的问题也发生在原始代码中。

1 个答案:

答案 0 :(得分:6)

我认为您使用

导致缓冲区溢出
char line[4];
fscanf(path_matr, " %[^\n]", line);

尝试更改为

fscanf(path_matr, " %3[^\n]", line);

或以其他方式减轻溢出的可能性。

字符宽度

确保您使用*(unicode 0x2a)而非(unicode 0xE2 0x88 0x97)作为分隔符。后者中较大的字符宽度会导致scanf()提前终止。 (当我在你的问题上复制并粘贴样本输入时,它包括更广泛的字符。)

执行此操作时,scanf()的最大字段宽度说明符并非绝对必要 - 但我仍然会使用它。

优化

当您使用-O2增加优化时matrix已经过优化 - 因此程序甚至不会尝试写入。

P.S。:你应该检查fopen()的返回值。