如何在C++中正确管理动态分配的指针数组?

3

我目前正在开发一个只有很小的RAM容量(128MB)的微处理器。为了分析性能,我运行了多个执行线程,但问题的核心在于如何将大量数据(浮点数和整数)存储在动态空间中,以减少在执行过程中向数据结构(如向量)所依赖的数据复制/分配。

为了解决这个问题,我决定在CLion上测试一些可能的方案,并编写了以下代码:

#include <cstdlib>
#include <cstdio>


int initial_capacity = 3;
int current_capacity = 3;
int current_count  = 0;

int*** initializeArray(){
    // initialize triple array space in memory
    int*** arr;
    /*
       3 items -> 3 data sets -> each data set starts with 3 spaces
       a "int arr[3][3][3]" but dynamically allocated
    */
    arr = (int***) calloc(current_capacity, sizeof(int**));
    for(int i = 0; i < current_capacity; i++){
        arr[i] = (int**) calloc(current_capacity, sizeof(int*));
        for(int j =0; j < current_capacity; j++){
            arr[i][j] = (int*) calloc(current_capacity,sizeof(int));
        }
    }
    return arr;
}


void resizeArray(int *** arr){
    auto max = (double) current_capacity;
    double percentage = current_count/max;
    if(percentage >= 0.5){
        for (int i = 0; i < initial_capacity; ++i) {
            for (int j = 0; j < initial_capacity; ++j) {
                current_capacity*=2;
                arr[i][j] = (int*) realloc(arr[i][j],(current_capacity)*sizeof(int));
            }
        }
    }
}

void deleteArrays(int *** arr){
    for (int i = 0; i < initial_capacity; ++i) {
        for (int j = 0; j < initial_capacity; ++j) {
            for (int k = 0; k < current_count; ++k) {
                arr[i][j][k] = NULL;
            }

        }
    }
    printf("Releasing allocated arrays 1\n");

    for (int i = 0; i < initial_capacity; ++i) {
        for (int j = 0; j < initial_capacity; ++j) {
            arr[i][j] = (int*) realloc(arr[i][j],sizeof(int));
            free(arr[i][j]);
        }
    }
    printf("Releasing allocated arrays 2\n");

    for (int i = 0;  i < initial_capacity; ++i) {
        free(arr[i]);
    }
    printf("Releasing allocated arrays 3\n");

    free(arr);
}


void printArrays(int *** arr){
    for (int i = 0; i < 3; ++i) {
        printf("Array[%d]\n", i);
        for (int j = 0; j < 3; ++j) {
            printf("Array[%d][%d]\nElements: ", i, j);
            for (int k = 0; k < current_count; ++k) {
                printf(" %d", arr[i][j][k]);
            }
            printf("\n");
        }
    }
    printf("\n");
}

int main() {
    int *** generated= initializeArray();
    int count  = 0;
    while (count < 21){
        if(count % 3 == 0) printArrays(generated);
        //verify
        resizeArray(generated);
        generated[0][0][current_count] = rand();
        generated[0][1][current_count] = rand();
        generated[0][2][current_count] = rand();
        generated[1][0][current_count] = rand();
        generated[1][1][current_count] = rand();
        generated[1][2][current_count] = rand();
        generated[2][0][current_count] = rand();
        generated[2][1][current_count] = rand();
        generated[2][2][current_count] = rand();

        current_count++;
        count++;
    }
    /* some operation with data collected */
    deleteArrays(generated);
    printf("Finished deleting dynamic arrays");
    return 0;
}

我尝试生成一个三重数组,以便在最后一个子集中存储相同数量的信息,同时增加其大小和总量。然而,数组的删除过程为了完成该过程的动态性总是导致进程以退出代码-1073740940(0xC0000374)结束,这是一个堆错误。我对此不是非常熟悉,希望得到任何有关它的反馈。


你尝试过添加调试语句以打印每个已分配/重新分配/删除的数组的原始指针吗?基于此,您应该能够检测到任何错误的删除。如果一切都对齐,请使用静态内存分析工具查找内存损坏。 - Sam Varshavchik
除了涉及语言之间的差异或交互的问题外,不要同时询问C和C ++。由于代码具有在C中无法工作的#include语句,因此我正在删除C标签。 - Eric Postpischil
@SamVarshavchik 我看了一些可能的语句,但通常我只能使用与地址的第一项有关的语句,在所有情况下它都返回一个有效的元素。不确定如何在其余分配的空间中进行验证。 - AICS2000
真的有必要使用三个不同的calloc调用来创建一个三维数组吗?有没有好的理由不使用一维数组并通过索引移位来完成其余部分?有时,只需一个大块的分配就可以极大地简化您的生活。此外,根据微处理器的不同,您可能会获得一些缓存局部性的好处 :) - hakononakani
@hakononakani 这是一个我之前不知道的概念。通常我只能在迭代序列中管理n-数组。我会研究一下的! - AICS2000
1个回答

3

在其内部循环的每次迭代中,例程resizeArray使用current_capacity*=2;使current_capacity加倍。第一次调用它时,这将导致arr [0] [0]被设置为指向6个int的内存,而循环继续并最终将current_capacity设置为1536。在程序执行的其余时间里,由于与current_capacity相关的阈值从未达到,resizeArray不会分配更多的内存。

同时,例程main继续向generated[0][0]写入越来越多的元素,将current_count增加到20,从而超出已分配内存的边界。

这个错误可以通过将current_capacity*=2;移到循环外部,在if(percentage >= 0.5)的“then”块内执行来修复。

另外请注意,将多维数组实现为指向指针或指向指针的指针的技术在时间和空间上是低效的。处理器对指针追踪的性能表现不佳。对于固定大小的多维数组,生产质量的代码不使用此技术。在需要一个可变的最后一维的情况下,选择可能不那么明确,但仍然可以优先使用一次连续的内存分配,并使用索引算术来计算数组中的位置,而不是指针查找。(对于可变长度数组,C使这相当简单,尽管对它们的支持是可选的。C++实现可能提供可变长度数组作为扩展,但必要的算术并不难,可以使用辅助函数或类完成。)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接