用于创建 HDF5 数据集的 4 维 c++ 数组的动态内存分配

Posted

技术标签:

【中文标题】用于创建 HDF5 数据集的 4 维 c++ 数组的动态内存分配【英文标题】:Dynamic memory allocation for 4 Dimensional c++ array to create HDF5 dataset 【发布时间】:2018-08-13 01:50:41 【问题描述】:

我在 QT 中有一个程序,它创建一个 HDF5 数据集并将其保存在磁盘中。

一开始我定义了这个数组:

int data[dataNumber][dataFilter][dataWidth][dataHeight];

dataNumber=400000,dataFilter=1,dataWidth=2,dataHeight=2 在这个循环中我在这个数组中设置了一个相同的值(当然是为了简单起见):

for (int i = 0; i < dataNumber; i++)
    for (int j = 0; j < dataFilter; j++)
        for (int k = 0; k < dataWidth; k++)
            for (int l = 0; l < dataHeight; l++)
                data[i][j][k][l]=2;

之后我使用这些命令创建了HDF5 数据集:

// Create a new file using the default property lists.
H5File file(FILE_NAME, H5F_ACC_TRUNC);

datadims[0] = dataNumber;
datadims[1] = dataFilter;
datadims[2] = dataWidth;
datadims[3] = dataHeight;

IntType datatype( PredType::NATIVE_INT );
datatype.setOrder( H5T_ORDER_LE );
DataSpace dataspace(4, datadims);

// Create the dataset.
DataSet dataset = file.createDataSet("data", datatype, dataspace);
dataset.write(data, PredType::NATIVE_INT);

一切都很好。

但是当我设置 dataWidth=4,dataHeight=4 时,segmentation fault 发生了,我认为堆栈的保留大小导致了这个问题,我应该使用 Dynamic memory allocation

所以我更改了data 数组,如下所示:

int ****data ;
data = new int***[dataNumber];
for( int i = 0 ; i < dataNumber ; i++ )

    data[i] = new int**[dataFilter] ;
    for( int j = 0 ; j < dataFilter ; j++ )
    
        data[i][j] = new int*[dataWidth] ;
        for( int k = 0 ; k < dataWidth ; k++ )
            data[i][j][k] = new int[ dataHeight ] ;
     

但是使用这个之后:

DataSet dataset = file.createDataSet("data", datatype, dataspace);
dataset.write(data, PredType::NATIVE_INT);

HDF5 数据集有很多错误的数字,例如 -1865382688 和 -1720619824,而不是 true number=2。

现在我不知道如何解决这个问题。我希望有人可以提供帮助。

【问题讨论】:

int data[dataNumber][dataFilter][dataWidth][dataHeight]; 是一块连续的内存。您在“修复”中所做的创建了大量指向不连贯的内存块的指针。 在你的程序中有dataNumberdataFilterdataWidthdataHeight常量吗? @RichardCritten 谢谢,你是对的,但我认为这不是我的问题。 @Bob__ 不,但如果我将它们用作常量变量,问题仍然存在。 【参考方案1】:

例如我们要创建数组 (2,2,3,4) 像这样:

enter code hereint a[2][2][3][3]=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18;"

所以我们可以像这样分配内存

enter code hereint**** data = new int***[2];for(int i = 0;  i < 2; i++)
data[i] = new int**[2];
    for (int j = 0; j < 3; j++)
        data[i][j]=new int*[3];
            for (int k=0;k<3;k++)
                data[i][j][k]= new int[3];
            
        
        
    

【讨论】:

【参考方案2】:

这是意料之中的:您正在传递一个指针数组(指向指针的指针),其中 HDF5 需要一个多维数组。 (有关内存布局差异的 ASCII 图形,请参阅我的answer to this other question。)如果您希望能够将内存传递给 HDF5,则必须将内存分配为单个块。

在 C++ 中,您需要像 Marko Popovic 建议的那样:

int* data = new int[dataNumber*dataFilter*dataWidth*dataHeight];

并自己进行索引计算。此处不再赘述。

当然,您可以将索引计算封装在某种宏或模板中,但无论哪种方式,在 C++ 中处理 4D 数组都是一个 PITA。


但是,如果您可以选择用 C 编写此代码,还有一个更好的选择:使用真正的 4D 数组。

int (*data)[dataFilter][dataWidth][dataHeight];
data = malloc(dataNumber*sizeof(*data));

这里,data 是一个指向 4D 数组的 3D slap 的指针,您分配 dataNumber 的此类 slap 以获得 4D 数组。有了这个,您可以像以前一样简单地索引 4D 数组:

data[i][j][k][l];

C 会为你做指数计算。

假设您的数组大小在编译时未知,这种方法在 C++ 中是不可能的,因为 C++ 要求所有数组长度都是编译时常量。 C 没有这个限制,从 C99 开始允许动态数组大小。

【讨论】:

非常感谢您评论的第一部分:它解决了我的问题。对于您评论的第二部分:我的GCC 编译器给我这一行的错误:data = malloc(dataNumber*sizeof(*data)); 并说invalid conversion from ‘void*’ to ‘int (*) 因为malloc 是一个空函数。我认为这行应该有一点改变。 @mortezaaliahmadi 如果您收到此错误,您正在将代码编译为 C++(使用 g++.cpp 文件),而不是 C(在 .c 文件上使用 gcc )。它们是不同的语言,C 确实将 void* 隐式转换为任何其他指针,而 C++ 不会。【参考方案3】:

我建议分配一块连续的内存,如下所示:

int *data = new int[dataNumber * dataFilter * dataWidth * dataHeight];

这意味着您将需要调用 new 运算符一次,而不是调用数千次。这也将使所有这些内存的清理变得容易,只需拨打一个电话:

delete []data;

而不是再次调用 delete 数千次。之后,您可以使用以下方式对数组进行索引:

data[((i*dataFilter + j)*dataWidth + k)*dataHeight + l];

【讨论】:

@cmaster 你是对的!我已经更新了修复这部分的答案。谢谢!

以上是关于用于创建 HDF5 数据集的 4 维 c++ 数组的动态内存分配的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 C++ 库在 HDF5 中找出数据集的 PredType

计算用于咖啡分类的HDF5数据集的平均值

如何从 C++ 中的 hdf5 文件中读取数据块?

从时间戳图像对创建 HDF5 数据集的最佳方法是啥?

使用 HDF5 C++ api 设置数据集的属性

C++ 代码创建空 HDF5 文件而不是数据集