假设磁盘上有五个二进制文件。这五个文件以二进制格式编码数字序列,只是它们都有不同的类型。假设它们是短INT、INT、LONG、FLOAT和DOUBLE。我们会让这些文件中存储不同数量的数字。
现在假设我有一个程序,当执行时,询问用户
输入要加载的文件名:
并且用户可以选择这五个文件中的一个。我希望程序将这些文件加载到数组中,以便可以执行进一步的计算。
我们可以假设存在两个函数:一个返回对文件的类型(即SHORT INT、INT、LONG、FLOAT或DOUBLE)进行编码的整数值(称之为"getfiletype"),另一个返回文件中的数字数量(例如1000、9338、8131、0等)(称其为"getfilesize")。条目的实际数量可能是数十亿个数字。如果可能的话,在程序中,我希望对数组使用相同的名称(比如"array"),该数组保存用户选择的任何文件的值。这样我就可以拥有像这样的区块
N=getfilesize("pickedfile.dat");
for(i=0 ; i<N ; i++ ) {
doublearray[i]==2.0*(double)array[i]+7.12;
}
可以变换数组。在这里,我引入了一个名为"doublearray"的新数组来保存转换后的值。然后,这个双数组要么被写入double格式的文件,要么在写入其他格式之前被转换。
我该怎么做这种事?完全困惑。
您的程序可以创建一个静态(或全局)void*数组,该数组将由对getfiletype()或getfilesize()的最新调用填充。然后,您必须对其进行适当的强制转换(正如您在示例中专门为加倍所做的那样)。假设您已经解决了文件数据方面的加载问题。
尽管这种方法在使用方面并不是很干净(依赖静态或全局会限制你进行不同对话的选择——特别是目前的情况,你必须确保你以顺序的方式进行操作)。
一个更清洁的API可能是这样的东西:
enum TypeEnum { SHORT_INT, INT, LONG, FLOAT, DOUBLE };
void* getfiledata(char *filename, unsigned int *size, TypeEnum *type);
#define GET_DATA_AND_CAST(filename, array, array_size)
do {
TypeEnum type;
void* arr = getfiledata(filename, array_size, &type);
switch(type) {
case SHORT_INT:
array = (short*)arr; break;
case INT:
array = (int*)arr; break;
case LONG:
array = (long*)arr; break;
case FLOAT:
array = (float*)arr; break;
case DOUBLE:
array = (double*)arr; break;
default:
// ASSERT
}
} while(0)
然后你可以像这样使用它:
void process_doubles(void *array) {
double to_conv[];
unsigned int size;
GET_DATA_AND_CAST("pickedfile.dat", to_conv, &size);
for(i=0; i<size; ++i ) {
doublearray[i] = 2.0 * to_conv[i] + 7.12;
}
}
IMHO C++会让这变得更好(因为你可以使用模板),但由于这个问题只标记有C,我只是在C.中提供选项
您可以使用void *
指针来存储指向任何数据类型的指针。
int num_elements = getfilesize();
size_t element_size;
switch (getfiletype()) {
case SHORT_INT: element_size = sizeof(short int); break;
...
}
void *array = malloc(num_elements * element_size);
...
void process_doubles(void *array) {
for(i=0 ; i<getfilesize("pickedfile.dat") ; i++ ) {
doublearray[i] = 2.0 * ((double *) array)[i] +7.12;
}
请注意,在对数组指针进行间接寻址之前,需要先强制转换数组指针。