我正在学习C并且因为我遇到分段错误而很难确定我做错了什么。 我试图初始化一个Matrix结构,其中包含一个指向具有实际数据的2D数组的指针。然后用数组中的数据填充它并打印出来。
#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;
}
此外,除了分段错误触发错误之外,还有什么可以改变?
答案 0 :(得分:3)
欢迎来到C.这里有两大问题:
1)您无法返回指向函数局部变量的指针。 (与make_matrix()
中的错误相关)
2)没有明显的方法可以在C中定义'multidimensional'数组,您可以方便地访问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;
}
但仅凭这一点无法解决这个问题。数据需要存储在一大类cols
* rows
元素中,您需要指定如何定位每个项目而不是data[x][y]
。
所以要解决2),你的Matrix结构定义应该是
struct Matrix {
int rows; // number of rows
int cols; // number of columns
double* data; // <- note that this is a pointer to one dim array
};
,以及make_matrix()
pmatrix->data = malloc(sizeof(double)*n_rows*n_cols);
就是你现在所需要的一切。
要复制具有相同维度和格式的矩阵,
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;
}
(我将此函数命名为dup_matrix()
而不是copy_matrix()
,因为它实际上会创建一个新实例)
最后,如果你想访问[x] [y]的元素,应该将位置显式计算为data[x*cols + y]
,这样printf()
行就会变为
printf("%f ", m->data[x*(m->cols) + y]);
当然,您需要正确检查malloc()
的返回错误并正确清理。
答案 1 :(得分:1)
以下内容:
Matrix* make_matrix(int n_rows, int n_cols) {
struct Matrix matrix;
将matrix
声明为函数make_matrix()
中的局部变量。在该函数的末尾附近,您获取该局部变量的地址,由于某种原因,您将其存储在指针中,然后返回该指针。因此,您将返回指向函数堆栈中的位置的指针。但该函数刚刚返回,因此该位置现在无效。
而不是struct Matrix matrix;
您需要执行Matrix* m = malloc( sizeof( Matrix ) );
(如果您的编译器不允许这样做,请尝试Matrix* m; m = malloc( sizeof( Matrix ) );
)然后按以下步骤填充结构:{{1}等等。
答案 2 :(得分:0)
感谢您的回复,我已经知道我失败了。 为了完整起见,工作代码如下所示:
#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; a row is an array of n_cols doubles
};
typedef struct Matrix Matrix;
Matrix* make_matrix(int n_rows, int n_cols) {
struct Matrix* matrix = malloc(sizeof(Matrix));
matrix->rows = n_rows;
matrix->cols = n_cols;
double** data = malloc(sizeof(double*) * n_rows);
for(int x = 0; x < n_rows; x++){
data[x] = calloc(n_cols, sizeof(double));
}
matrix->data = data;
return matrix;
}
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[n_cols*x+y];
}
}
return matrix;
}
void print_matrix(Matrix* m) {
for(int x = 0; x < m->rows; x++) {
printf("%s", "\n");
for(int y = 0; y < m->cols; y++) {
printf("%f\t", m->data[x][y]);
}
}
}
void matrix_test(void) {
double a[] = {
1, 2, 3,
4, 5, 6,
7, 8, 9,
10,11,12
};
Matrix* m1 = copy_matrix(a, 4, 3);
print_matrix(m1);
}
int main(void) {
base_init();
base_set_memory_check(true);
matrix_test();
return 0;
}
如果有更多改进,或者会影响你的想法,请告诉我。