在动态分配的2D数组上使用realloc()是个好主意吗?

在动态分配的2D数组上使用realloc()是个好主意吗?,c,arrays,memory-management,multidimensional-array,malloc,C,Arrays,Memory Management,Multidimensional Array,Malloc,我主要感兴趣的是缩小这样一个阵列的可行性 我正在从事一个项目,在该项目中,我使用单个malloc()调用来创建单个中等大小的二维数组。(每个阵列最多只有几十个MiB。)问题是,在其中一个阵列的生命周期内,其内容的大小急剧缩小(缩小了一半以上)。显然,在程序的生命周期中,我可以不考虑数组大小。(这只是一个有GiB内存可用的系统上的x MiB。)但是,我们谈论的是,在程序终止之前,超过一半的分配空间会被废弃,并且,由于我使用数组的性质,所有幸存的数据都保存在一组连续的行中(在块的开头)。如果我真的不

我主要感兴趣的是缩小这样一个阵列的可行性


我正在从事一个项目,在该项目中,我使用单个malloc()调用来创建单个中等大小的二维数组。(每个阵列最多只有几十个MiB。)问题是,在其中一个阵列的生命周期内,其内容的大小急剧缩小(缩小了一半以上)。显然,在程序的生命周期中,我可以不考虑数组大小。(这只是一个有GiB内存可用的系统上的x MiB。)但是,我们谈论的是,在程序终止之前,超过一半的分配空间会被废弃,并且,由于我使用数组的性质,所有幸存的数据都保存在一组连续的行中(在块的开头)。如果我真的不需要那只公羊的话,那就把它拿在手上简直是浪费

虽然我知道realloc()可以用来收缩动态创建的数组,但二维数组更复杂。我想我理解它的内存布局(当我实现构造它的函数时),但这将限制我对该语言及其编译器工作的理解。显然,我必须处理行(并处理行指针),而不仅仅是字节,但我不知道这一切的结果有多可预测

是的,我需要用一个malloc()创建数组。所讨论的对象有几百万行。我尝试在每一行分别使用一个循环到malloc(),但程序总是冻结在100000 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;
}
char**alloc\u 2d\u arr(整数,整数){
/*((行指针字节+(数据字节))*/
char**mtx=malloc(rnum*sizeof(char*)+rnum*cnum*sizeof(char));
/*初始化指向其行的第一个单元格的每一行指针*/
字符*p=(字符*)(mtx+rnum);
对于(int i=0;i
使用多维数组,可以使用或不使用指向可变长度数组的指针来完成此操作。由于您可能不想分配任何额外内存,因此将就地完成此操作

首先分配一个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;
如果要更改列计数,则必须移动元素。因为我们不需要复制第一列,所以复制从第二列开始。函数memmove用于避免内存重叠,在这种情况下不会发生内存重叠,但如果新列计数更大,则会发生内存重叠。此外,它还可以避免别名问题。请注意s代码的定义仅因为我们正在使用分配的内存。让我们将列计数更改为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 );
int(*newarray)[3]=(int(*)[3])数组;
对于(尺寸j=1;j<15;j++)
memmove(newarray[j],array[j],sizeof(int)*3);
newarray=realloc(数组,sizeof(int)*15*3);
工作示例:


如果新列计数恰好大于旧列计数,则必须首先重新分配内存(以获得更多空间),然后进行列复制,而不是从最后一列开始。

realloc
对于如此大的表不是一个好主意,请查看“avl”和“红黑”树。“如果我真的不需要那只公羊的话,那么把它抓起来似乎是一种浪费。"-第一个配置文件。第二,realloc存在触发将所有内部数据复制到不同页面的高风险,您仅因试图保存自己声称的ram而产生的非琐碎费用并不是一个真正的问题。这里唯一的赢家方案是
realloc
保持与您的内存相同的区域头y基,并且尾页被返回用于其他用途;某些东西
realloc
无法保证……。因此,您是否考虑过只分配2(或3或4,无论什么)个分配,记住您最终保留了哪些分配,并且
free()
-在事件发生后,将不再需要的分配给您?即“保留”矩阵的一半在第一个分配中,另一半在另一个分配中,最终你只释放了另一半。如果你不知道,如果你愿意稍微重新构造代码,前导的指针块是不必要的。去掉它可以节省很多空间。我承认这一点很丢脸,但我很抱歉在理解
int(*array)[10]=malloc(…);
时遇到困难。基于我对C的明显理解不足,这看起来像是用一个取消引用的指针作为其标识符初始化一个新创建的变量。取消引用三个指针(两次)并给出malloc()输出,但将类型放在前面会使其看起来像RAM地址被用作符号(这没有意义)。我觉得我在学习C时看到了这一切,但用谷歌搜索相关术语显然会产生不好的结果。@CircleSquared它是指向多维数组的指针。在我的示例中是二维的。如下所示:
int a[7][9];int(*pa)[9]=a;
,除了在我的示例中,我没有将指针指向自动数组,而是指向已分配的内存。感谢您向我展示了一种更有效的方法,除了简单地回答我的问题之外,还可以动态分配多维数组。因此,它足够安全,但这是设置数组的更好方法。
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 );