MST

星途 面试题库

面试题:C语言结构体文件读写错误处理的优化

假设你有一个复杂的结构体,其中包含指针成员,在进行文件读写操作时,如何全面且高效地检查可能出现的错误?比如内存分配失败、文件打开失败、读写偏移错误等。请详细阐述你的思路,并给出关键代码片段。此外,如何确保在跨平台情况下,这些错误检查机制依然有效?
22.8万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

思路阐述

  1. 内存分配失败:在使用malloccallocrealloc等分配内存函数后,立即检查返回值是否为NULL。若为NULL,表示内存分配失败,应进行相应错误处理,如记录日志、释放已分配资源并退出程序。
  2. 文件打开失败:使用fopen打开文件时,检查返回值是否为NULL。若为NULL,表示文件打开失败,可通过perror获取错误信息并处理。
  3. 读写偏移错误:在使用fseekftell等函数操作文件偏移量时,检查函数返回值。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;
}

跨平台考虑

  1. 文件操作函数:尽量使用标准C库中的文件操作函数(如fopenfreadfwritefseekftell等),这些函数在不同操作系统上有统一的接口和行为。
  2. 错误处理:标准C库中的perror函数在不同平台上都能提供与系统相关的错误信息。若需要更详细的错误处理,可使用errno变量获取错误码,不同平台上errno的定义是标准化的,可根据其值进行相应处理。
  3. 内存分配:使用标准C库的malloccallocrealloc函数,它们在不同平台上行为一致,返回NULL表示内存分配失败。同时,注意释放内存时使用free函数,避免内存泄漏。