如何将动态分配的 3D 数组写入 C 中的 hdf5 文件?

How to write dynamically allocated 3D array into hdf5 file in C?

我有一个动态分配的 3D 数组,实现为 指向数组指针数组的指针(至少这是我对我正在做的事情的解释)并想存储该数据在一个 hdf5 文件中。虽然文件中存储了一些东西,但它不是原始数据。

这是我的代码(这里省略了错误检查的内容):

#include <stdlib.h>
#include <stdio.h>
#include <hdf5.h>

double ***arr3D_d( size_t dim1, size_t dim2, size_t dim3 ) {
    size_t  ii, jj;
    double  ***arr;

    arr = calloc( (size_t)dim1, sizeof(double**) );
    for ( ii=0 ; ii<dim1 ; ++ii ) {
        arr[ii] = calloc( (size_t)(dim2*dim3), sizeof(double*) );
        for ( jj=0 ; jj<dim2 ; ++jj ) {
            arr[ii][jj] = calloc( (size_t)(dim3), sizeof(double) );
        }
    }
    return arr;
}

int main( int argc, char *argv[] ) {
    size_t  ii, jj, kk,
            dim1, dim2, dim3;
    double  ***arr3D;

    // hdf5 related variables
    hid_t   file_id, dataset_id, dataspace_id;
    hsize_t dims[3];
    herr_t  status;

    dim1    = 2;
    dim2    = 3;
    dim3    = 4;
    arr3D   = arr3D_d( dim1, dim2, dim3 );

    for (ii=0 ; ii<dim1 ; ++ii)
        for (jj=0 ; jj<dim2 ; ++jj)
            for (kk=0 ; kk<dim3 ; ++kk)
                arr3D[ii][jj][kk]   = ii + jj + kk;

    for (ii=0 ; ii<dim1 ; ++ii)
        for (jj=0 ; jj<dim2 ; ++jj)
            for (kk=0 ; kk<dim3 ; ++kk)
                printf( "arr3D[%ld][%ld][%ld] = %f\n", 
                        ii, jj, kk, arr3D[ii][jj][kk] ); 

    // create new file for hdf5 data to be written into
    file_id = H5Fcreate( "data.h5", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT );
    // create simple dataspace for the dataset
    dims[0] = dim1;
    dims[1] = dim2;
    dims[2] = dim3;
    dataspace_id    = H5Screate_simple( 3, dims, NULL );
    // create dataset
    dataset_id      = H5Dcreate( file_id, "dataset", H5T_NATIVE_DOUBLE, dataspace_id, 
        H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT );
    // write the dataset
    status          = H5Dwrite( dataset_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, 
        H5P_DEFAULT, arr3D[0][0] );
    // terminate access and free identifiers
    status          = H5Dclose(dataset_id);
    status          = H5Sclose(dataspace_id);
    status          = H5Fclose(file_id);

    return 0;
}

我现在用h5dump输出数据时,是这样写的:

HDF5 "data.h5" {
GROUP "/" {
   DATASET "dataset" {
      DATATYPE  H5T_IEEE_F64LE
      DATASPACE  SIMPLE { ( 2, 3, 4 ) / ( 2, 3, 4 ) }
      DATA {
      (0,0,0): 0, 1, 2, 3,
      (0,1,0): 0, 2.42092e-322, 1, 2,
      (0,2,0): 3, 4, 0, 2.42092e-322,
      (1,0,0): 2, 3, 4, 5,
      (1,1,0): 0, 5.58294e-322, 4.64561e-310, 4.64561e-310,
      (1,2,0): 4.64561e-310, 0, 0, 0
      }
   }
}
}

这与代码中的 arr3D 不对应,后者在 运行 时间内打印到控制台 - 输出为:

arr3D[0][0][0] = 0.000000
arr3D[0][0][1] = 1.000000
arr3D[0][0][2] = 2.000000
arr3D[0][0][3] = 3.000000
arr3D[0][1][0] = 1.000000
arr3D[0][1][1] = 2.000000
arr3D[0][1][2] = 3.000000
arr3D[0][1][3] = 4.000000
arr3D[0][2][0] = 2.000000
arr3D[0][2][1] = 3.000000
arr3D[0][2][2] = 4.000000
arr3D[0][2][3] = 5.000000
arr3D[1][0][0] = 1.000000
arr3D[1][0][1] = 2.000000
arr3D[1][0][2] = 3.000000
arr3D[1][0][3] = 4.000000
arr3D[1][1][0] = 2.000000
arr3D[1][1][1] = 3.000000
arr3D[1][1][2] = 4.000000
arr3D[1][1][3] = 5.000000
arr3D[1][2][0] = 3.000000
arr3D[1][2][1] = 4.000000
arr3D[1][2][2] = 5.000000
arr3D[1][2][3] = 6.000000

如上所述,这不是写入 hdf5 文件的内容。我做错了什么?

垃圾值的原因是在 HDF5 文件中存储指针而不是实际的双精度值。为了很好地存储连续分配的数组,最简单的方法是使用指向可变长度数组 (VLA) 的指针分配 3d 数组。只需将所有分配代码替换为以下行:

 double (*arr3D)[dim2][dim3] = calloc(dim1, sizeof *arr3D);

就这些了。

记得调用free(arr3D)释放它。

与普遍的看法相反,将 VLA 添加到 C 的主要原因是为了简化处理多维数组,而不是用于运行时定义大小的对象的堆栈分配。

当使用 H5Dwrite() 存储数组时,只传递 arr3D 作为最后一个参数。

修改后的hdf5文件内容为:

HDF5 "data.h5" {
GROUP "/" {
   DATASET "dataset" {
      DATATYPE  H5T_IEEE_F64LE
      DATASPACE  SIMPLE { ( 2, 3, 4 ) / ( 2, 3, 4 ) }
      DATA {
      (0,0,0): 0, 1, 2, 3,
      (0,1,0): 1, 2, 3, 4,
      (0,2,0): 2, 3, 4, 5,
      (1,0,0): 1, 2, 3, 4,
      (1,1,0): 2, 3, 4, 5,
      (1,2,0): 3, 4, 5, 6
      }
   }
}