在函数中为结构分配内存,该结构返回指向struct的指针

时间:2019-02-14 10:08:09

标签: c

我正在尝试创建一个表示二维数学矩阵的结构。

函数'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;
}

我在做什么错了?

4 个答案:

答案 0 :(得分:6)

由于data是指向某个内存区域的指针,因此您将不得不单独分配该区域,即

ptr = (Matrix *)malloc(sizeof(Matrix));
ptr->data = (double *)malloc(sizeof(double)*rows*cols);

请注意,您还必须同时在freemptr->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)

您需要分别为数据和矩阵分配内存。另外,您还应该释放initMatrixmain()函数内部分配的内存。

除了提到所有其他关于使用memset()calloc()而不是自己在2个for循环中自己做的事情等所有非常好的答案之外,我还要提及其他海报未回答的几件事,也为了抓住要点,我感觉到操作员在问什么:

  1. 您正在使一个需要double **data的矩阵与一个包含相同数量元素并且可以存储在double *data中的1-d向量混淆。

    我猜这就是为什么您使用两个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;并获得所需的任何输出,包括全零。

答案 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的大小,您最好将sizeofoffsetof与结构类型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获得零初始化内存。