使用单次调用 malloc 为 C 89/90 中未知数据类型的二维数组动态分配连续的内存块

dynamically allocate contiguous block of memory for 2D array of unknown data type in C 89/90 using single call to malloc

我必须动态分配一个连续的存储块来保存任意数据类型的二维数组。
它只能使用一次调用 malloc.
部分内存必须包含 "pointer to data type" 的混合数据类型和数据类型本身。
任意数据类型称为 Type。 完全披露:是的,这是一项任务。为了弄清楚这一点,我已经为此苦苦思索了 30 多个小时。我不能使用 C99+ 标准。它必须是 Pre-C99。

到目前为止我有这个:

Type **Create2D(size_t rows, size_t cols) {
    Type **ptr = (Type **)SafeMalloc(rows * sizeof(Type*) + rows * cols * sizeof(Type)); 
    //  rows*sizeof(Type*) is total memory needed for the elements to store the pointers. 
    //  rows*cols*sizeof(Type) is the memory needed to store the actual array data
    //  The sum of the above two gives the total amount of contiguous memory needed

    int index;
    for (index = 0; index < (int)rows; index++)
        ptr[index] = &ptr + rows*sizeof(Type *) + index * cols * sizeof(Type);
        //  in my mind, this assigns the pointers to the address of each column
        //  to the first address blocks allocated by malloc
}

Type 数据类型由提供的头文件使用 typedef 定义如下:

#define ELEMENTS 9
typedef signed char Type[ELEMENTS];
#undef ELEMENTS

SafeMalloc 函数只包含错误检查和 malloc 调用

static Type **SafeMalloc(size_t size) {
    void *vp;       
    if ((vp = malloc(size)) == NULL) {
        fputs("Out of memory\n", stderr);
        exit(EXIT_FAILURE);
    }
    return(vp);
}

我的 Create2D 函数从 main 调用如下,其中 rowscols 设置为 for 循环提供的不同值,以便它们通过列出的每个 运行代码在这里:

Type **ppobj;
int rows, cols;
ppobj = Create2D((size_t)rows, (size_t)cols);

数组在此处的另一个循环中被调用和测试:

int x = Test2D(ppObj, rows, cols);

定义为:

int Test2D(Type **ppObj, int dim0, int dim1) {
    signed char testValue;
    int row, col, ix;       
    Type item;

    testValue = SCHAR_MIN;  
    for (row = 0; row < dim0; ++row) {
        for (col = 0; col < dim1; ++col) {
            for (ix = 0; ix < (int)(sizeof(item) / sizeof(item[0])); ++ix) {                
                ppObj[row][col][ix] = testValue;
                //  throws an exception in above step while stepping through at col = 1.
                if (testValue == SCHAR_MAX)
                    testValue = SCHAR_MIN;
                else
                   ++testValue;
            }
        }
    }
    ....
}

最后,我觉得我所拥有的已经很接近了。给定一个 1x27 数组,它将通过此​​操作,但是当我调用释放内存的函数然后调用 2x26 数组时,它将在上述步骤中出错。它进入了 3x25 阵列并且在上面也出现了错误。我的免费功能如下所示:

void Free2D(void *ptr) {
    free(ptr);
}

它是使用这个语法调用的,来自上面的主函数:

Free2D((void *)ppObj);

我也 运行 它通过并看到 dim1 变量在嵌套的 for 循环中间从它的设置值从传递的参数变化到像 1830342 或一些种类。这让我相信我没有正确使用 free() 函数。

您的代码几乎是正确的,计算 ptr[index] 的公式不正确:您必须计算从 ptr 转换为字节指针的字节偏移量。

这是一个更好的版本:

Type **Create2D(size_t rows, size_t cols) {
    Type **ptr = (Type **)SafeMalloc(rows * sizeof(Type*) + rows * cols * sizeof(Type)); 
    //  rows*sizeof(Type*) is total memory needed for the elements to store the pointers. 
    //  rows*cols*sizeof(Type) is the memory needed to store the actual array data
    //  The sum of the above two gives the total amount of contiguous memory needed

    size_t index;
    for (index = 0; index < rows; index++) {
        ptr[index] = (Type*)((unsigned char*)ptr + rows * sizeof(Type *) + index * cols * sizeof(Type));
       //  in my mind, this assigns the pointers to the address of each column
       //  to the first address blocks allocated by malloc
    }
    return ptr;
}

仍然存在潜在的对齐问题:Type 可能需要比 Type* 更严格的对齐。为了解决这个问题,您可以单独计算索引大小,并将数据部分对齐到 Type:

大小的倍数
Type **Create2D(size_t rows, size_t cols) {
    size_t index_size = (size_t)((unsigned long long)(rows * sizeof(Type*)) * sizeof(Type) / sizeof(Type));
    Type **ptr = (Type **)SafeMalloc(index_size + rows * cols * sizeof(Type)); 
    //  index_size is total memory needed for the elements to store the pointers. 
    //  rows*cols*sizeof(Type) is the memory needed to store the actual array data
    //  The sum of the above two gives the total amount of contiguous memory needed

    size_t index;
    for (index = 0; index < rows; index++) {
        ptr[index] = (Type*)((unsigned char*)ptr + index_size + index * cols * sizeof(Type));
    }
    return ptr;
}