函数内存分配问题

时间:2019-05-13 17:23:17

标签: c segmentation-fault

编译并运行该函数后,我遇到了段错误:11.我相信应该正确执行malloc,所以不确定为什么会出现段错误。任何见解将不胜感激!

typedef struct matrix matrix;

struct matrix {
   unsigned int n_rows;
   unsigned int n_cols;
   float **entries;
};

//refer to matrix.h
matrix *matrix_zero(unsigned int n_rows, unsigned int n_cols){
  struct matrix* new = (struct matrix*)malloc(sizeof(struct matrix));
  new->entries = malloc(n_rows * n_cols * sizeof(float));
  new->n_rows=n_rows;
  new->n_cols=n_cols;
  for(int x = 0; x < n_rows; x++){
    for(int y = 0; y < n_cols; y++){
      new->entries[x][y] = 0;
    }
  }
  return new;
}

/* main: run the evidence functions above */
 int main(int argc, char *argv[])
 {
   struct matrix* test1 = matrix_zero(3,3);
   // matrix_show(test1);
 }

2 个答案:

答案 0 :(得分:4)

问题似乎出在您为matrix->entries分配的位置上。该结构定义了一个指向指针的指针,但是您要分配一个浮点指针float*float**。您需要分配n_rowsfloat*,并且每个分配点都指向n_colsfloat值的分配。例如:

int i;
// No error checking shown here
new->entries = malloc(sizeof(float*) * n_rows);
for (i = 0; i < n_rows; i++) {
    new->entries[i] = malloc(sizeof(float) * n_cols);
}

答案 1 :(得分:0)

您已经为rows分配了cols大小的数组,但是编译器无法知道每一行的实际行大小,因此符号entries[i]确实期望有一个指向简单浮点数组而不是二维数组的指针。这是与n维数组和C语言中的指针数组在结构上的主要区别之一。仅当完全限定数组维的大小(例如,将其声明为float entries[N][M];时,编译器才知道如何为它定维- -看起来您不能在维度中使用变量表达式,只能使用静态编译时常量)

您在这里有两种方法:

  • 使用一维数组并根据行大小计算索引:

    typedef struct matrix matrix;
    
    struct matrix {
        unsigned int n_rows;
        unsigned int n_cols;
        float *entries;  /* we make this to point to a single array of n_rows * n_cols entries */
    };
    
    
    new->entries = malloc(n_rows * n_cols * sizeof(float));
    new->n_rows=n_rows;
    new->n_cols=n_cols;
    for(int x = 0; x < n_rows; x++){
        for(int y = 0; y < n_cols; y++){
            new->entries[x * n_cols + y] = 0.0; /* entry position should be as shown */
    }
    
  • 使用n_cols个条目的单个行数组(这已经在@joel的另一个答案中显示了)

    typedef struct matrix matrix;
    
    struct matrix {
        unsigned int n_rows;
        unsigned int n_cols;
        float **entries;  /* this time the entries field points to an array of pointers to float. */
    };
    
    new->entries = malloc(n_rows * sizeof *new->entries);  /* individual cells are 'float *', not 'float' this time. */
    new->n_rows=n_rows;
    new->n_cols=n_cols;
    for(int x = 0; x < n_rows; x++){
        new->entries[x] = malloc(n_cols* sizeof **new->entries); /* this time float *'s are here */
        for(int y = 0; y < n_cols; y++){
            new->entries[x][y] = 0; /* entry position should be as shown */
        }
    }
    

两种方法都有说明:

  • 第一个方法仅需要一个malloc(3)用于entrys数组,因此这使得分配和取消分配更加容易,但是某些实现可能会限制单个malloc(3)的实际大小分配巨大的矩阵。这使得整个矩阵的重新分配也更加容易。

  • 第二种方法仅需要n_rows个指针的malloc和n_rows n_colsfloat的malloc。这样就可以分配庞大的矩阵(您永远不会将整个矩阵分配到一个块中),但是必须先分配所有行,然后再分配指向行的指针数组,然后再分配矩阵结构。

    < / li>
  • 我建议您使用malloc(n_cols * sizeof *new->entries)而不是malloc(n_cols * sizeof (float *)),因此,如果您更改new->entries的定义类型,则无需更改此表达式。 p>

最后,认为C语言在调用函数方面没有魔力。您可能错误地假设使malloc( n_rows * n_cols * sizeof(float) )自动将指针转换为二维数组,但是那里没有魔术,malloc(3)是一个普通的C函数,就像您可以编写的那样,这就是为什么它需要实际的字节数,而不是数组的尺寸(以元素为单位)的原因。