我正在尝试创建一个表示二维数学矩阵的结构。
函数'initMatrix'旨在初始化n行x n列的矩阵,并将元素存储在动态分配的double数组中并设置为零。
但是,当我尝试通过取消引用结构(according to this question)中的“数据”指针为数组分配零时,这将导致程序失败。
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int rows;
int cols;
double *data;
} Matrix;
Matrix *initMatrix(int rows, int cols)
{
Matrix *ptr;
ptr = (Matrix *)malloc(sizeof(int) * 2 + sizeof(double) * rows * cols);
if(ptr == NULL) printf("Couldn't allocate memory");
for(int i = 0; i < rows; i++) {
for(int j = 0; j < cols; j++) {
*(ptr->data) = 0; //error originating here
ptr->data++;
}
}
return ptr;
}
int main(void)
{
Matrix *mptr = initMatrix(2, 2);
return 0;
}
我在做什么错了?
答案 0 :(得分:6)
由于data
是指向某个内存区域的指针,因此您将不得不单独分配该区域,即
ptr = (Matrix *)malloc(sizeof(Matrix));
ptr->data = (double *)malloc(sizeof(double)*rows*cols);
请注意,您还必须同时在free
和mptr->data
上调用mptr
,以返回所有堆分配的内存。
话虽如此,您可能想通过从Matrix
返回Matrix *
而不是initMatrix
来简化程序。然后,您只需要关心分配/释放data
成员:
Matrix initMatrix(int rows, int cols)
{
Matrix result;
result.data = (double *)malloc(sizeof(double) * rows * cols);
if(result.data == NULL) printf("Couldn't allocate memory");
result.rows = rows;
result.cols = cols;
// initialization of result.data here, consider using memset() ...
return result;
}
要将内存初始化为零,您可能需要使用memset而不是离散循环。
答案 1 :(得分:2)
ptr = (Matrix *)malloc(sizeof(int) * 2 + sizeof(double) * rows * cols);
您应该为ptr->data
而不是ptr
这样做。
取消引用data
失败是因为您从未为其分配内存,所以它指向的是无处可寻(准确地说,是未定义的行为)。
因此,首先分配一个Matrix
,然后分配data
所需的内容
ptr = malloc(sizeof(Matrix));
ptr -> data = malloc(sizeof(int) * 2 + sizeof(double) * rows * cols);
答案 2 :(得分:2)
您需要分别为数据和矩阵分配内存。另外,您还应该释放initMatrix
中main()
函数内部分配的内存。
除了提到所有其他关于使用memset()
或calloc()
而不是自己在2个for
循环中自己做的事情等所有非常好的答案之外,我还要提及其他海报未回答的几件事,也为了抓住要点,我感觉到操作员在问什么:
您正在使一个需要double **data
的矩阵与一个包含相同数量元素并且可以存储在double *data
中的1-d向量混淆。
我猜这就是为什么您使用两个for
循环。您不希望1行中包含4个元素。您需要2行和2个列!您可以查看下面的代码以了解如何实现。
请记住同时释放mptr
和data
。
此外,您的代码中没有初始化ptr->cols
和ptr->rows
。
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int rows;
int cols;
double **data;
} Matrix;
Matrix *initMatrix(int rows, int cols)
{
Matrix *ptr;
ptr = (Matrix *)malloc(sizeof(Matrix));
ptr->cols = cols;
ptr->rows = rows;
ptr->data = (double**)malloc(sizeof(double*) * rows);
for(int i = 0; i < rows; i++) {
ptr->data[i] = (double*)malloc(sizeof(double) * cols);
for(int j = 0; j < cols; j++) {
ptr->data[i][j] = i*10+j;
// printf("%d,%d,%lf", i, j, ptr->data[i][j]); // just for debugging
}
}
return ptr;
}
int main(void)
{
Matrix *mptr = initMatrix(2, 2);
printf("rows:%d, cols:%d\n", mptr->rows, mptr->cols);
for (int i=0; i<2; i++) {
for (int j=0; j<2; j++) {
printf("element[%d][%d]:%lf\n",i,j,mptr->data[i][j]);
}
}
free(mptr->data);
free(mptr);
return 0;
}
产生输出:
我刚刚显示要调试的行数:2,列数:2
元素[0] [0]:0.000000
元素[0] [1]:1.000000
元素[1] [0]:10.000000
元素[1] [1]:11.000000
。您可以更改行ptr->data[i][j] = i*10+j;
并获得所需的任何输出,包括全零。
答案 3 :(得分:1)
如果您想用一个malloc
分配整个结构,则可以使用
typedef struct
{
int rows;
int cols;
double data[1];
} Matrix;
与其他答案相反,这允许使用单个free
。
如果编译器支持大小为0的数组,则也可以使用double data[0];
。
从C99开始,您可以使用结构中没有维的数组:double data[];
,请参见https://stackoverflow.com/a/2061038/10622916
与其通过添加结构字段类型的大小来计算malloc
的大小,您最好将sizeof
或offsetof
与结构类型Matrix
一起使用,因为可能有些填充。 (可能不是您这种情况,但这取决于编译器的实现和您的结构字段。)
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h> // for offsetof
typedef struct
{
int rows;
int cols;
double data[1];
// or with C99: double data[];
} Matrix;
Matrix *initMatrix(int rows, int cols)
{
Matrix *ptr;
double *data;
ptr = (Matrix *)malloc(
offsetof(Matrix, data) // = size of Matrix without double data[1];
// with C99's "double data[];" or with the non-standard
// "double data[0];" you can replace offsetof(...) with: sizeof(Matrix)
+ sizeof(double) * rows * cols); // dynamic array size
if(ptr == NULL) {
perror("malloc failed");
} else {
// save rows and columns for later accessing the matrix
ptr->rows = rows;
ptr->cols = cols;
data = ptr->data;
for(int i = 0; i < rows; i++) {
for(int j = 0; j < cols; j++) {
*(data) = 0;
data++;
}
}
}
return ptr;
}
int main(void)
{
Matrix *mptr = initMatrix(2, 2);
// use matrix
// a single free is sufficient with the approach above
free(mptr); mptr = NULL;
return 0;
}
您可以计算数组索引,而不是增加指针data
for(int i = 0; i < rows; i++) {
for(int j = 0; j < cols; j++) {
ptr->data[i * cols + j] = 0;
}
}
或者对于0初始化,您可以使用memset
memset(ptr->data, 0, sizeof(double) * rows * cols);
或者使用calloc(1, offsetof(Matrix, data) + sizeof(double) * rows * cols);
代替malloc
获得零初始化内存。