如何将动态分配的 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
}
}
}
我有一个动态分配的 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
}
}
}