Cir*_*red 5 c arrays malloc memory-management multidimensional-array
我主要对缩小这样一个数组的可行性感兴趣.
我正在开发一个项目,我使用单个malloc()调用来创建各个中等大小的2D数组.(每个只有几十个MiB,最大的.)问题是,在其中一个阵列的生命周期中,其内容大小缩小(超过一半).显然,我可以在程序的生命周期中单独保留数组大小.(它只有一个具有GiB RAM的系统上的x MiB.)但是,我们正在谈论超过一半的分配空间在程序终止之前就被废弃了,并且,由于我使用的方式的性质数组中,所有幸存数据都保存在一组连续的行中(在块的开头).如果我真的不需要它,那么抓住所有RAM似乎是浪费.
虽然我知道realloc()可用于缩小动态创建的数组,但2D数组更复杂.我想我理解它的内存布局(因为我实现了构造它的函数),但这推动了我对语言及其编译器工作的理解的极限.显然,我将不得不处理行(并处理行指针),而不仅仅是字节,但我不知道所有这些的结果是多么可预测.
而且,是的,我需要使用单个malloc()创建数组.有问题的对象有几百万行.我尝试分别使用一个循环到malloc()每一行,但程序总是冻结在大约100,000 malloc()s.
对于后台,我用来构造这些数组的源代码如下:
char ** alloc_2d_arr(int cnum, int rnum) {
/* ((bytes for row pointers + (bytes for data)) */
char **mtx = malloc(rnum * sizeof (char *) + rnum * cnum * sizeof (char));
/* Initialize each row pointer to the first cell of its row */
char *p = (char *) (mtx + rnum);
for (int i = 0; i < rnum; i++) {
mtx[i] = p + i * cnum;
}
return mtx;
}
Run Code Online (Sandbox Code Playgroud)
使用多维数组,可以使用或不使用指向可变长度数组的指针来完成此操作。由于您可能不想分配任何额外的内存,因此这将就地完成。
首先分配一个 20 x 10 的数组:
int ( *array )[10] = malloc( sizeof(int ) * 20 * 10 );
for( size_t i = 0 ; i < 20 ; i++ )
for( size_t j = 0 ; j < 10 ; j++ )
array[i][j] = i * 100 + j;
Run Code Online (Sandbox Code Playgroud)
如果要更改行数,则不必移动任何元素,只需要重新分配。将行数更改为 15 很简单:
array = realloc( array , sizeof( int ) * 15 * 10 );
Run Code Online (Sandbox Code Playgroud)
如果要更改列数,则必须移动元素。由于我们不需要复制第一列,因此复制从第二列开始。函数 memmove 用于避免内存重叠,这种情况在这种情况下不会发生,但如果新列数更大,则可能会发生。它还可以避免混叠问题。请注意,定义此代码只是因为我们正在使用分配的内存。让我们将列数更改为 3:
int (*newarray)[3] = ( int(*)[3] )array;
for( size_t j = 1 ; j < 15 ; j++ )
memmove( newarray[j] , array[j] , sizeof( int ) * 3 );
newarray = realloc( array , sizeof( int ) * 15 * 3 );
Run Code Online (Sandbox Code Playgroud)
工作示例: https: //ideone.com/JMdJO0
如果新列数恰好大于旧列数,则必须首先重新分配内存(只是为了获得更多空间),然后将进行列复制,而不是从最后一列开始。