思路阐述
- 内存分配失败:在使用
malloc
、calloc
、realloc
等分配内存函数后,立即检查返回值是否为NULL
。若为NULL
,表示内存分配失败,应进行相应错误处理,如记录日志、释放已分配资源并退出程序。
- 文件打开失败:使用
fopen
打开文件时,检查返回值是否为NULL
。若为NULL
,表示文件打开失败,可通过perror
获取错误信息并处理。
- 读写偏移错误:在使用
fseek
、ftell
等函数操作文件偏移量时,检查函数返回值。fseek
成功返回0,失败返回非零值;ftell
成功返回当前文件位置,失败返回-1
。
关键代码片段
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 假设的复杂结构体
typedef struct {
int id;
char *name;
double value;
} ComplexStruct;
// 写入文件函数
void writeToFile(const char *filename, ComplexStruct *data, size_t count) {
FILE *file = fopen(filename, "wb");
if (file == NULL) {
perror("Failed to open file for writing");
return;
}
for (size_t i = 0; i < count; i++) {
// 检查name指针是否为空,避免写入空指针造成未定义行为
if (data[i].name == NULL) {
fprintf(stderr, "Invalid name pointer at index %zu\n", i);
continue;
}
size_t nameLen = strlen(data[i].name);
if (fwrite(&data[i].id, sizeof(int), 1, file) != 1) {
perror("Failed to write id");
break;
}
if (fwrite(&nameLen, sizeof(size_t), 1, file) != 1) {
perror("Failed to write name length");
break;
}
if (fwrite(data[i].name, sizeof(char), nameLen, file) != nameLen) {
perror("Failed to write name");
break;
}
if (fwrite(&data[i].value, sizeof(double), 1, file) != 1) {
perror("Failed to write value");
break;
}
}
if (fclose(file) != 0) {
perror("Failed to close file after writing");
}
}
// 读取文件函数
ComplexStruct* readFromFile(const char *filename, size_t *count) {
FILE *file = fopen(filename, "rb");
if (file == NULL) {
perror("Failed to open file for reading");
*count = 0;
return NULL;
}
// 预分配一定数量的结构体空间,可根据实际情况调整
size_t initialCapacity = 10;
ComplexStruct *data = (ComplexStruct*)malloc(initialCapacity * sizeof(ComplexStruct));
if (data == NULL) {
perror("Failed to allocate memory for data");
fclose(file);
*count = 0;
return NULL;
}
size_t index = 0;
while (1) {
if (index >= initialCapacity) {
initialCapacity *= 2;
ComplexStruct *tmp = (ComplexStruct*)realloc(data, initialCapacity * sizeof(ComplexStruct));
if (tmp == NULL) {
perror("Failed to reallocate memory for data");
free(data);
fclose(file);
*count = 0;
return NULL;
}
data = tmp;
}
if (fread(&data[index].id, sizeof(int), 1, file) != 1) {
if (feof(file)) {
break;
}
perror("Failed to read id");
free(data);
fclose(file);
*count = 0;
return NULL;
}
size_t nameLen;
if (fread(&nameLen, sizeof(size_t), 1, file) != 1) {
perror("Failed to read name length");
free(data);
fclose(file);
*count = 0;
return NULL;
}
data[index].name = (char*)malloc((nameLen + 1) * sizeof(char));
if (data[index].name == NULL) {
perror("Failed to allocate memory for name");
free(data);
fclose(file);
*count = 0;
return NULL;
}
if (fread(data[index].name, sizeof(char), nameLen, file) != nameLen) {
perror("Failed to read name");
free(data[index].name);
free(data);
fclose(file);
*count = 0;
return NULL;
}
data[index].name[nameLen] = '\0';
if (fread(&data[index].value, sizeof(double), 1, file) != 1) {
perror("Failed to read value");
free(data[index].name);
free(data);
fclose(file);
*count = 0;
return NULL;
}
index++;
}
if (fclose(file) != 0) {
perror("Failed to close file after reading");
}
*count = index;
return data;
}
跨平台考虑
- 文件操作函数:尽量使用标准C库中的文件操作函数(如
fopen
、fread
、fwrite
、fseek
、ftell
等),这些函数在不同操作系统上有统一的接口和行为。
- 错误处理:标准C库中的
perror
函数在不同平台上都能提供与系统相关的错误信息。若需要更详细的错误处理,可使用errno
变量获取错误码,不同平台上errno
的定义是标准化的,可根据其值进行相应处理。
- 内存分配:使用标准C库的
malloc
、calloc
、realloc
函数,它们在不同平台上行为一致,返回NULL
表示内存分配失败。同时,注意释放内存时使用free
函数,避免内存泄漏。