[英]Allocating memory for a structure within a function which returns pointer to struct
我正在嘗試創建一個表示二維數學矩陣的結構。
函數“ initMatrix”用於初始化n行x n列的矩陣,並將元素存儲在動態分配的double數組中,並設置為零。
但是,當我嘗試通過取消引用結構中的“數據”指針為數組分配零時(根據此問題) ,這將導致程序失敗。
#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;
}
我究竟做錯了什么?
由於data
是指向某個內存區域的指針,因此您將不得不單獨分配該區域,即
ptr = (Matrix *)malloc(sizeof(Matrix));
ptr->data = (double *)malloc(sizeof(double)*rows*cols);
注意,你也會有叫free
上mptr->data
以及對mptr
到底返回所有堆分配的內存。
話雖如此,您可能想通過從initMatrix
返回Matrix
而不是Matrix *
來簡化程序。 然后,您只需要關心分配/釋放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而不是離散循環。
ptr = (Matrix *)malloc(sizeof(int) * 2 + sizeof(double) * rows * cols);
您應該為ptr->data
而不是ptr
執行此操作。
取消引用data
失敗是因為您從未為它分配內存,所以它指向的是無處可尋(准確地說,是未定義的行為)。
因此,首先分配一個Matrix
,然后分配data
所需的data
ptr = malloc(sizeof(Matrix));
ptr -> data = malloc(sizeof(int) * 2 + sizeof(double) * rows * cols);
您需要分別為數據和矩陣分配內存。 另外,您還應該在main()
initMatrix
函數內部分配的內存。
除了所有其他關於使用memset()
或calloc()
而不是自己在2 for
循環中自己做的事情都提到的非常好的答案之外,我還想提到其他一些海報沒有回答的事情,並抓住要點,我感覺OP在問:
您將需要double **data
的矩陣與包含相同數量元素並且可以存儲在double *data
的一維向量混淆。
我猜這就是為什么要同時使用兩個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;
並獲得所需的任何輸出,包括全零。
如果您想用一個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
的大小, offsetof
將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
以獲得零個初始化內存。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.