【问题标题】:Difficulty creating a contiguous 2D array on the heap难以在堆上创建连续的二维数组
【发布时间】:2016-04-09 00:16:26
【问题描述】:

我目前正在堆上实现floats 的 N x 2 矩阵,如下所示:

float **matrix = malloc(sizeof(float*) * n_cols);

for (int i = 0; i < n_cols; ++i) {
    matrix[i] = malloc(sizeof(float) * 2);
}

matrix 的元素在内存中不连续,使得这个数据结构缓存不友好(据我理解)。我正在尝试重写上面的内容以在堆上创建一个真正的二维数组。根据之前的一些 SO 帖子,我尝试了以下方法:

float (*matrix)[2] = malloc(sizeof(float) * n_cols * 2);

但是,当我运行我的代码时,这会导致分段错误。

【问题讨论】:

  • 连续是什么意思?您可以在一个卡盘中分配它,但您访问它的方式将决定缓存的友好性。
  • @Pemdas 连续我的意思是类似于二维数组在堆栈上的存储方式,即所有元素都相互连接,因此从一行的末尾到另一行的开头不会需要内存跳跃。
  • 您的示例是正确的,您没有显示重现问题的代码。

标签: c arrays segmentation-fault malloc


【解决方案1】:

如果你希望整个数组是连续的,那么你需要如下声明它。

  float *matrix = malloc(n1 * n2 * sizeof(float));

这有帮助吗?请注意分配矩阵的第二种方式。

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
  size_t r = 0;
  size_t c = 0;
  int rows    = 82;
  int columns = 30;
  float *matrix = malloc(rows * columns * sizeof(float));
  for(r = 0; r < rows; r++) {
    printf("%zu - ", r); 
    for(c = 0; c < columns; c++) {
      printf("%zu|", c); 
      matrix[r + r*c] = 1.0;
    }   
    printf("\n"); 
  }

  float **matrix2 = malloc(rows * sizeof(float*));

  for(r = 0; r < rows; r++) {
    matrix2[r]    = malloc(columns * sizeof(float));
  }
  for(r = 0; r < rows; r++) {
    printf("%zu - ", r); 
    for(c = 0; c < columns; c++) {
      printf("%zu|", c); 
      matrix2[r][c] = 1.0;
    }   
    printf("\n"); 
  }
  free(matrix);
  for(r = 0; r < rows; r++) {
    free(matrix2[r]);    
  }
  free(matrix2);
  return 0;
}   

您可以在此处找到带有代码的基准...

https://github.com/harryjackson/doc/blob/master/c/cache_locality_2d_array_test.c

【讨论】:

  • 理想情况下我想保留双下标,这样我就不必更改我的其余代码。
【解决方案2】:

我想你想要这样的东西。

float ** matrix = malloc(sizeof(float) * ((n_col * 2) + (n_col * sizeof(float*));

for(i = 0; i < n_col; i++)
{
    matrix[i] = matrix + (n_col *sizeof(float*)) + ((i * 2) *sizeof(float)); 
}

矩阵的大小是 2* n_col,但是矩阵的第一个索引将是指向列的指针。您必须为这些指针分配额外的空间。这就是 (n_col * sizeof(float *)) 发挥作用的地方。每行的大小为 (2 * sizeof(float)),因此矩阵中第一个索引的每个都需要指向距离最后一个字节的内存数组 (2 * sizeof(float))。

看起来像这样。

米[0]米[1]米[2] 矩阵 矩阵 + 1 * (2 * sizeof(float)) 矩阵 + 2 * (2 * sizeof(float))

第二个索引将一个位置引用到 m[x] 指向的内存中。

【讨论】:

  • 您能详细解释一下吗?我不明白+ n_col in malloc.
猜你喜欢
  • 1970-01-01
  • 2021-08-01
  • 2019-01-05
  • 2017-08-18
  • 1970-01-01
  • 1970-01-01
  • 2011-04-30
  • 1970-01-01
  • 2019-03-16
相关资源
最近更新 更多