链接列表分段错误

时间:2014-08-17 23:18:12

标签: c matrix linked-list segmentation-fault binaryfiles

我必须创建代表矩阵的链表。 在第一个链表中,我有行coordonate,到下一个节点的链接和到另一个结构的链接,该结构包含列coordonate,到下一个节点的链接以及这些coordonates中矩阵的数字值。以下是我可能更明确的不同结构。

#include "sparsemat.h"
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

int main() {
    matrix* tempMatrix = (matrix*)malloc(sizeof(matrix));
    tempMatrix = sp_read("mat_100x5");
    return 0;
}

struct matrix* sp_read(char* path) {
    matrix* matrice = (matrix*)malloc(sizeof(matrix));
    matrice->rowFirst = NULL;
    matrice->nRows = 0;
    matrice->nCols = 0;
    row* rows = (row*)malloc(sizeof(row));
    rows->indiceRow = 0;
    rows->data = NULL;
    rows->next = NULL;
    col* cols = (col*)malloc(sizeof(col));
    cols->value = 0, 0;
    cols->indiceColumn = 0;
    cols->next = NULL;

    FILE* file = NULL;
    file = fopen(path, "rb");

    int nRow;
    int nCol;

    fread(&nRow, sizeof(int), 1, file);
    fread(&nCol, sizeof(int), 1, file);
    printf("%d , %d \n", nRow, nCol);

    int i;
    int j;

    double* currentDigit = (double*)malloc(sizeof(double));
    int count;

    for (i = 1; i <= nRow; i++) {
        if (i == 1) { // initialize the matrix
            matrice->nRows = nRow;
            matrice->nCols = nCol;
            matrice->rowFirst = rows;
        }

        rows = pushRow(NULL, &i, matrice);
        count = 0;
        for (j = 1; j <= nCol; j++) {
            fread(currentDigit, sizeof(double), 1, file);

            if (*(currentDigit) != 0.0) {
                count++;
                if (count == 1) { // begin a new column list on the next node of
                                  // the row list
                    cols = NULL;
                    rows->data = cols;
                }
                cols = pushCol(&j, currentDigit, cols);
            }
        }
    }

    fclose(file);
    free(currentDigit);
    return matrice;
}

row* pushRow(col* data, int* rows, matrix* top) {
    row* f = NULL;
    f = (row*)malloc(sizeof(row));

    if (f == NULL) {
        exit(EXIT_FAILURE);
    }

    f = top->rowFirst;

    if (f->indiceRow == 0) {
        printf("null");
        f->data = data;
        f->indiceRow = *(rows);
        f->next = NULL;
    }
    else {
        while (f->next != NULL) {
            f = f->next;
        }
        row* temp = NULL;
        temp = (row*)malloc(sizeof(row));
        f->next = temp;
        f->next->indiceRow = *(rows);
        f->next->data = data;
        f = f->next;
    }

    return f;
}

col* pushCol(int* column, double* value, col* dataRow) {
    col* f = NULL;
    f = (col*)malloc(sizeof(col));

    if (f == NULL) {
        exit(EXIT_FAILURE);
    }

    f = dataRow;
    if (f->indiceColumn == 0) {
        f->indiceColumn = *(column);
        f->value = *(value);
        dataRow = f;
    }
    else {
        while (f->next != NULL) {
            f = f->next;
        }
        col* temp = NULL;
        temp = (col*)malloc(sizeof(col));
        f->next = temp;
        f->next->indiceColumn = *(column);
        f->next->value = *(value);
        f = f->next;
        dataRow = f;
    }

    return dataRow;
}

程序在第35行执行nRows和nCols的printf,但是我收到了分段错误(核心转储)。 我希望我的问题很明确,在此先感谢您的帮助!

1 个答案:

答案 0 :(得分:2)

由于您没有向我们展示rowcolmatrix的结构定义,因此无法可靠地编译代码。这个问题很糟糕。这也意味着很难猜测数据应该如何组织。看起来你对磁盘文件中的每个数据项都有一个值,但是数据中有足够的零,值得制作一个稀疏矩阵(基于缺少的头文件名中的提示)。

main()中,您有内存泄漏:

matrix* tempMatrix = (matrix*)malloc(sizeof(matrix));
tempMatrix = sp_read("mat_100x5");

您从tempMatrix分配malloc(),然后使用sp_read()的结果覆盖它。但是,这不是核心转储问题。

sp_read()中,您应该在使用返回的文件指针之前检查fopen()是否有效。但是,如果第一个fread()不起作用,你就会崩溃,所以你现在正在逃避它,但不检查fopen()是不好的做法,因为它失败了。同样,您应该检查每个fread()以确保获取数据。如果你不这样做,你不应该继续假设你有价值观。同样,如果分配失败,您应该检查每个内存分配的结果并避免崩溃。

在C中,数组边界从0 ... N-1开始,而不是1 .. N.你有:

for (i = 1; i <= nRow; i++) {
    if (i == 1) { // initialize the matrix
        matrice->nRows = nRow;
        matrice->nCols = nCol;
        matrice->rowFirst = rows;
    }

循环应为for (i = 0; i < nRow; i++)。与列上的循环类似。

初始化代码应该在循环之外。

pushCol()中的代码是另一组内存泄漏:

col* pushCol(int* column, double* value, col* dataRow) {
    col* f = NULL;
    f = (col*)malloc(sizeof(col));

    if (f == NULL) {
        exit(EXIT_FAILURE);
    }

    f = dataRow;

您将malloc()的结果分配给f;然后用f中的值覆盖dataRow,从而泄漏刚刚分配的内存。将f初始化为null然后分配malloc()的结果是毫无意义的(但最基本的优化编译器将为您解决这个问题)。只需将malloc()的结果直接分配到f

pushRow()中的代码同样泄漏了内存:

row* pushRow(col* data, int* rows, matrix* top) {
    row* f = NULL;
    f = (row*)malloc(sizeof(row));

    if (f == NULL) {
        exit(EXIT_FAILURE);
    }

    f = top->rowFirst;

pushCol()的接口应该更简单;列号和值都不需要是指针 - 您可以通过值传递两者。 pushRow()的界面可以int rows代替int *rows

顺便说一句,写作:

 cols->value = 0, 0;

是一种轻微的浪费;它指定0,但不需要逗号运算符。 (这可能会混淆在您的本地语言环境中将0,0写为零,但在C中,如果包含小数点,则需要编写0.0,如果不包含小数点,则该空格将是错误的使用逗号运算符。)


我为稀疏矩阵类型生成了一组定义,如下所示:

typedef struct col col;
typedef struct row row;
typedef struct matrix matrix;

struct col
{
    int     indiceColumn;
    double  value;
    col    *next;
};

struct row
{
    int  indiceRow;
    col *data;
    row *next;
};

struct matrix
{
    row *rowFirst;
    int  nRows;
    int  nCols;
};

我还编写了一个程序来在文件中生成一个非常稀疏的单位矩阵:

#include <stdio.h>

int main(void)
{
    int nRows = 5;
    int nCols = 10;

    fwrite(&nRows, sizeof(nRows), 1, stdout);
    fwrite(&nCols, sizeof(nCols), 1, stdout);
    for (int i = 0; i < nRows; i++)
    {
        for (int j = 0; j < nCols; j++)
        {
            double d = (i == j) ? 1.0 : 0.0;
            fwrite(&d, sizeof(d), 1, stdout);
        }
    }
    return 0;
}

在数据文件中,程序启动但在pushCol()解除引用fif (f->indiceColumn == 0))时崩溃,强烈指示空指针。

查看调用代码:

        if (*(currentDigit) != 0.0) {
            count++;
            if (count == 1) { // begin a new column list on the next node of
                              // the row list
                cols = NULL;
                rows->data = cols;
            }
            cols = pushCol(&j, currentDigit, cols);

我们可以看到传递给函数时cols是一个空指针。在函数内部,即参数dataRow,它被分配给f,因此您将取消引用空指针。这不是什么大惊喜;这是一个非常常见的崩溃原因。

要修复

您将需要重新访问所有内存分配代码,确保不泄漏内存,并更仔细地决定应该分配哪些代码的数据。坦率地说,目前这是一个混乱 - 很难遵循预期的逻辑。看起来每行应该是非零列的链表。使用单位矩阵的数据,每行将具有从其链接的单个列值。但我不相信你已经为所有行结构分配了足够的空间,或者正确地分配了列。