如何确保二维数组在内存中连续分配

Posted

技术标签:

【中文标题】如何确保二维数组在内存中连续分配【英文标题】:How to ensure a 2D array is allocated contigously in memory 【发布时间】:2020-01-18 09:09:10 【问题描述】:

我正在通过 MPI 发送一个 2D 数组,为了使其正常工作,该数组需要在内存中连续分配。

我是这样分配的:

int **array;
array = malloc(size1 * sizeof( *(array) );
for (int k = 0; k < size1; k++)
    array[k] = malloc(size2 * sizeof(**(array));

那我想用:

MPI_Send(array, size1*size2, MPI_INT, target_pe, tag, MPI_COMM_WORLD);

如何确保数组是连续分配的?

目前我正在尝试这个:

for (int k = 0; k < size1; k++)
    MPI_Send(array[k], size2, MPI_INT, target_pe, tag, MPI_COMM_WORLD);

这会导致稍后在程序的不相关部分中出现段错误。但是,如果我将元素一一发送,它就可以工作。

【问题讨论】:

你不能那样做。顺便说一句,这不是二维数组,而是指针数组 *(int) 的意思是 *array 吗?否则没有多大意义。 另外,您尝试创建的是jagged array。您可以分配一个 size1 * size2 元素数组并使用简单的算术来访问这些元素。 Correctly allocating multi-dimensional arrays 的可能重复项。 确实应该是*(array),我修好了。因此,如果我 malloc (size*size2 * sizeof int) 那将是一个一维数组并且使用 MPI 的行为与预期一样,但我的程序始终访问数组 [i] [j],因此它需要进行重大重构。我在当前方法中添加了一些其他问题。 【参考方案1】:

如何确保二维数组在内存中连续分配

一步分配。

示例使用支持可变长度数组的 C99 代码。这里使用了一个指向 VLA 的指针。

// ptr is a pointer to a 2D array
int (*ptr)[size1][size2] = malloc(sizeof *ptr); 
(*ptr)[0][0] = 1;            // One corner of the 2D array
(*ptr)[size-1][size-1] = 2;  // Opposite corner of the 2D array

稍后我将研究示例 MPI() 代码。

【讨论】:

【参考方案2】:

用途:

int (*array)[size2] = malloc(size1 * sizeof *array);
if (!array) Handle error…

如果size2 不是常量并且您的 C 实现不支持可变长度数组,则使用:

int *array = malloc(size1 * size2 * sizeof *array);
if (!array) Handle error…

在这种情况下,您将不得不使用手动地址算法来访问数组元素。代替array[i][j],使用array[i*size2 + j]

【讨论】:

我想我最终可能会重构代码以将其实现为一维数组并使用适当的算术对其进行索引。因为它可能是通过 MPI 发送它的“最安全”的方式【参考方案3】:

您无法通过对malloc() 的顺序调用来确保这一点。你可以做的是,你可以从内存中的开头分配malloc(size1 * size2) 空间,然后你可以按照你的意愿分割分配的缓冲区。你现在可以说array[i]实际上是内存中的array[i * size2]

【讨论】:

【参考方案4】:

正确的方法是在一次操作中为二维数组分配内存。那么由于数组在 C 中并不是真正的一等公民,更不用说多维数组了,你必须为指针数组分配内存并使其元素指向每一行的开头:

int *mem = malloc(sizeof(*mem) * size1 * size2);
int **array = malloc(size1 * sizeof(*array));
for (int k = 0; k < size1; k++) 
    array[k] = mem + k * size2 * sizeof(*mem);

这将确保在将数组传递给期望的例程时进行连续分配,并且仍然允许以array[i][j]; 访问元素

【讨论】:

在此之后我在释放内存时遇到问题。循环中的 free(array[k]) 会导致错误,并且我无法在释放例程中访问 int *mem。 @jsb:只需使用free(array [0]);。通过构造,array[0] mem. sizeof(*mem) * size1 * size2 优于 size1 * size2 * sizeof(*mem)size1,size2 应该是 intsize1 * size2 可能会溢出第二个并且可能不是第一个,因为第一个使用至少 size_t 数学。 一般来说,做一个指针数组并不是一个好主意。虽然这允许写入array[col][row],但它可能会降低性能,并且内存是连续的这一事实并不能得到隐式保证。相反,您应该只使用mem[col * size2 + row] 应该是array[k] = mem + k * size2;(长话短说,指针算术)。

以上是关于如何确保二维数组在内存中连续分配的主要内容,如果未能解决你的问题,请参考以下文章

试图将一个连续的动态二维数组从 C 传递到 Fortran

试图将一个连续的动态二维数组从 C 传递到 Fortran

c语言问题:c语言中二维数组在内存中怎样存储?

C语言动态分配二维字符串数组

c++中二维数组的内存分配

二维内核中的银行冲突