C 矩阵结构

Joh*_*lba 4 c arrays structure matrix segmentation-fault

我正在学习 C 并且很难确定我做错了什么,因为我遇到了分段错误。我正在尝试初始化一个矩阵结构,该结构包含一个指向具有实际数据的二维数组的指针。然后用数组中的数据填充它并打印它。

#include "base.h" 

struct Matrix {
    int rows; // number of rows
    int cols; // number of columns
    double** data; // a pointer to an array of n_rows pointers to rows
};
typedef struct Matrix Matrix;

Matrix* make_matrix(int n_rows, int n_cols) {
    struct Matrix matrix;
    matrix.rows = n_rows;
    matrix.cols = n_cols;
    matrix.data = (double**)malloc(sizeof(double*) * n_rows);
    for(int x = 0; x < n_rows; x++){
        matrix.data[x] = (double*)calloc(n_cols, sizeof(double));
    }
    struct Matrix *m;
    m = &matrix;
    return m;
}

Matrix* copy_matrix(double* data, int n_rows, int n_cols) {
    struct Matrix *matrix = make_matrix(n_rows, n_cols);
    for(int x = 0; x < n_rows; x++) {
        for(int y = 0; y < n_cols; y++) {
            matrix->data[x][y] = data[x+y];
        }
    }
    return matrix;
}

void print_matrix(Matrix* m) {
    for(int x = 0; x < m->rows; x++) {
        for(int y = 0; y < m->cols; y++) {
            printf("%f", m->data[x][y]);
        }
    }
}

void matrix_test(void) {

    double a[] = { 
        1, 2, 3, 
        4, 5, 6, 
        7, 8, 9 };
    Matrix* m1 = copy_matrix(a, 3, 3);
    print_matrix(m1);
}

int main(void) {
    base_init();
    base_set_memory_check(true);
    matrix_test();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

另外,除了segmentation fault触发错误还有什么可以改的更好?

小智 5

欢迎来到 C。这里有两个大问题:

1) 不能返回指向函数局部变量的指针。(与错误有关make_matrix()

2) 没有明显的方法可以在 C 中定义“多维”数组,您可以方便地访问像 那样的元素data[x][y],除非您的行大小在编译时已知并固定。(并且您的矩阵维度在编译时未知。)

让我们分别处理它们。

要解决1),您想要做的make_matrix()实际上是:

Matrix* make_matrix(int n_rows, int n_cols) {
    struct Matrix* pmatrix = malloc(sizeof(struct Matrix));
    pmatrix->rows = n_rows;
    pmatrix->cols = n_cols;
    ...
    ...
    return pmatrix;
}
Run Code Online (Sandbox Code Playgroud)

但仅此而已并不能修复该错误。数据需要存储在一个由cols*rows元素组成的大数组中,并且您需要指定如何定位每个项目而不是data[x][y].

所以要解决 2),你的矩阵结构定义应该是

struct Matrix {
    int rows; // number of rows
    int cols; // number of columns
    double* data; // <- note that this is a pointer to one dim array
};
Run Code Online (Sandbox Code Playgroud)

,和里面 make_matrix()

pmatrix->data = malloc(sizeof(double)*n_rows*n_cols);
Run Code Online (Sandbox Code Playgroud)

就是你现在所需要的。

要复制相同维度和格式的矩阵,

Matrix* copy_matrix(double* data, int n_rows, int n_cols) {
    struct Matrix *matrix = make_matrix(n_rows, n_cols);
    for(int i = 0; i < n_rows*n_cols; i++)
        matrix->data[i] = data[i];
    return matrix;
}
Run Code Online (Sandbox Code Playgroud)

(我将这个函数命名为 asdup_matrix()而不是copy_matrix()因为它实际上创建了一个新实例)

最后,如果您想访问 [x][y] 处的元素,则位置应明确计算为data[x*cols + y],因此该printf()行变为

printf("%f ", m->data[x*(m->cols) + y]);
Run Code Online (Sandbox Code Playgroud)

当然,您需要正确检查返回malloc()错误并正确清理。


Mik*_*kis 2

下列:

Matrix* make_matrix(int n_rows, int n_cols) {
    struct Matrix matrix;
Run Code Online (Sandbox Code Playgroud)

在 function 中声明matrix为局部变量make_matrix()。在该函数末尾附近,您获取该局部变量的地址,出于某种原因将其存储在指针中,然后返回该指针。因此,您将返回一个指向函数堆栈中的位置的指针。但该函数刚刚返回,因此该位置现在无效。

而不是struct Matrix matrix;您需要做的Matrix* m = malloc( sizeof( Matrix ) );(如果您的编译器不允许这样做,则尝试Matrix* m; m = malloc( sizeof( Matrix ) );)然后继续按如下方式填充您的结构:m->rows = n_rows;等等。

  • 另外 `matrix-&gt;data[x][y] = data[x+y];` -&gt; `matrix-&gt;data[x][y] = data[n_rows*x+y];` (2认同)