簡體   English   中英

在函數中為結構分配內存,該結構返回指向struct的指針

[英]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);

注意,你也會有叫freemptr->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在問:

  1. 您將需要double **data的矩陣與包含相同數量元素並且可以存儲在double *data的一維向量混淆。

    我猜這就是為什么要同時使用兩個for循環的原因。 您不希望1行中包含4個元素。 您要2行2列! 您可以查看下面的代碼以了解如何實現。

  2. 記住要同時mptrdata

  3. 另外,在代碼中,您沒有初始化ptr->colsptr->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的大小, offsetofsizeofoffsetof與結構類型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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM