我主要感兴趣的是缩小这样一个数组的可行性。
我正在做一个项目,我使用单个malloc()调用来创建单独的中等大小的2D数组。(每个阵列最多只有几十个MiB。)问题是,在其中一个阵列的使用寿命内,其内容的大小急剧缩小(缩小了一半以上)。显然,在程序的生命周期中,我可以不考虑数组大小。(在GiB RAM可用的系统上,这只是一个xMiB。)但是,我们谈论的是,在程序终止之前,一半以上的分配空间就被废弃了,而且,由于我使用数组的性质,所有幸存的数据都保存在一组连续的行中(在块的开头)。如果我真的不需要的话,保留所有的RAM似乎是一种浪费。
虽然我知道realloc()可以用来收缩动态创建的数组,但2D数组更复杂。我想我理解它的内存布局(当我实现构建它的函数时),但这超出了我对语言及其编译器工作的理解。显然,我必须处理行(并处理行指针),而不仅仅是字节,但我不知道这一切的结果会有多可预测
是的,我需要用一个malloc()创建数组。有问题的对象有几百万行。我试着使用一个循环来分别对每一行执行malloc(),但程序总是在100000个malloc)左右冻结。
对于背景,我用来构建这些阵列的来源如下:
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;
}
使用多维数组,这可以在有或没有指向可变长度数组的指针的情况下完成。由于您可能不想分配任何额外的内存,所以这将在适当的位置完成。
首先分配一个20乘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;
如果要更改行数,则不必移动任何元素,只需需要一个realloc。将行计数更改为15是微不足道的:
array = realloc( array , sizeof( int ) * 15 * 10 );
如果要更改列数,则必须移动元素。由于我们不需要复制第一列,所以复制从第二列开始。函数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 );
工作示例:https://ideone.com/JMdJO0
如果新列计数恰好大于旧列计数,则必须首先重新分配内存(以获得更多空间),然后进行列复制,而不是从最后一列开始。