You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用fwrite写入结构体至二进制文件时出现冗余数据问题求助

问题根源分析与修复方案

你遇到的二进制文件出现额外目录路径类信息的问题,核心是**fwrite的参数完全用错了**,而且代码里还有几个严重的未初始化和内存分配问题,导致写入了随机的内存垃圾(那些奇怪的路径信息其实是堆内存里的残留数据)。

先逐个揪出代码里的致命问题:

  • typedef语法错误:你写的struct student{...}typedef student;是反的,正确写法应该是typedef struct student {...} student;
  • 未初始化变量numberOfStudents:你直接用它来malloc内存,但这个变量根本没赋值,会导致分配随机大小的内存,后续操作全是未定义行为
  • fwrite的size参数完全错误:
    • 写ID的时候,你用了sizeof(struct student)作为每个元素的大小,但ID是int类型,应该用sizeof(int)
    • 写name和secondName的时候,你同样错误地用了sizeof(struct student),而char类型的大小是sizeof(char)(也就是1),这会导致每次写入时,把远大于实际字符串长度的内存块写到文件里,堆里的垃圾数据(比如路径)就被一起写进去了
  • 文件名内存分配未考虑结束符:scanf("%s")会自动给字符串加\0,但你只分配了numberOfcharacter字节的内存,没有留这个结束符的位置,会导致缓冲区溢出
  • fflush(stdin)是未定义行为:C标准里fflush只能用于输出流,用在stdin上会导致不可预测的结果
  • student指针未初始化就访问成员:你malloc了student数组,但根本没给里面的name、secondName等成员赋值,直接用strlen读取的是随机内存数据,这也是垃圾数据的来源

修复后的完整代码

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

// 修正typedef语法
typedef struct student {
    int ID;
    char name[30];
    char secondName[30];
    double mark;
} student;

int main() {
    FILE *fp;
    student *studentArr;
    int numberOfStudents;
    char *filename;
    int numberOfCharacters;

    // 先获取学生数量,初始化变量
    printf("Enter the number of students: ");
    if (scanf("%d", &numberOfStudents) != 1 || numberOfStudents <= 0) {
        fprintf(stderr, "Invalid number of students!\n");
        exit(EXIT_FAILURE);
    }

    // 分配学生数组内存
    studentArr = malloc(numberOfStudents * sizeof(student));
    if (studentArr == NULL) {
        perror("Memory error allocating students");
        exit(EXIT_FAILURE);
    }

    // 先输入每个学生的信息(之前你完全没做这一步!)
    for (int i = 0; i < numberOfStudents; i++) {
        printf("\nEnter details for student %d:\n", i+1);
        printf("ID: ");
        scanf("%d", &studentArr[i].ID);
        // 清理输入缓冲区的换行
        while (getchar() != '\n');
        printf("First name: ");
        fgets(studentArr[i].name, sizeof(studentArr[i].name), stdin);
        // 去掉fgets带来的换行符
        studentArr[i].name[strcspn(studentArr[i].name, "\n")] = '\0';
        printf("Second name: ");
        fgets(studentArr[i].secondName, sizeof(studentArr[i].secondName), stdin);
        studentArr[i].secondName[strcspn(studentArr[i].secondName, "\n")] = '\0';
        printf("Mark: ");
        scanf("%lf", &studentArr[i].mark);
    }

    // 获取文件名
    printf("\nEnter the number of characters of the filename: ");
    if (scanf("%d", &numberOfCharacters) != 1 || numberOfCharacters <= 0) {
        fprintf(stderr, "Invalid filename length!\n");
        exit(EXIT_FAILURE);
    }
    // 多分配1字节存'\0'
    filename = malloc((numberOfCharacters + 1) * sizeof(char));
    if (filename == NULL) {
        perror("Memory error allocating filename");
        exit(EXIT_FAILURE);
    }
    // 清理输入缓冲区
    while (getchar() != '\n');
    printf("Write the name of your bin file: ");
    fgets(filename, numberOfCharacters + 1, stdin);
    filename[strcspn(filename, "\n")] = '\0';

    // 打开二进制文件
    if ((fp = fopen(filename, "wb")) == NULL) {
        perror("Error creating file");
        exit(EXIT_FAILURE);
    }

    // 正确写入每个字段
    for (int i = 0; i < numberOfStudents; i++) {
        // 写入ID:size是int的大小,count是1
        if (fwrite(&studentArr[i].ID, sizeof(int), 1, fp) != 1) {
            perror("Error writing ID");
            break;
        }
        // 写入名字长度
        int lenOfName = strlen(studentArr[i].name);
        if (fwrite(&lenOfName, sizeof(int), 1, fp) != 1) {
            perror("Error writing name length");
            break;
        }
        // 写入名字:size是char的大小,count是长度
        if (fwrite(studentArr[i].name, sizeof(char), lenOfName, fp) != lenOfName) {
            perror("Error writing name");
            break;
        }
        // 写入姓氏长度
        int lenOfSecondName = strlen(studentArr[i].secondName);
        if (fwrite(&lenOfSecondName, sizeof(int), 1, fp) != 1) {
            perror("Error writing second name length");
            break;
        }
        // 写入姓氏
        if (fwrite(studentArr[i].secondName, sizeof(char), lenOfSecondName, fp) != lenOfSecondName) {
            perror("Error writing second name");
            break;
        }
        // 写入分数:size是double的大小,count是1
        if (fwrite(&studentArr[i].mark, sizeof(double), 1, fp) != 1) {
            perror("Error writing mark");
            break;
        }
    }

    // 释放资源
    free(filename);
    free(studentArr);
    if (fp != NULL) {
        fclose(fp);
    }

    return 0;
}

关键修复点解释

  1. 修正fwrite参数:每个字段的size参数必须是该字段类型的大小,比如int用sizeof(int),char用sizeof(char),这样才会准确写入对应长度的数据,不会把堆里的垃圾带进去。
  2. 初始化所有变量:给numberOfStudents赋值,并且先输入学生的信息(你之前的代码完全没给student数组的成员赋值,直接读取strlen是读随机内存)。
  3. 修复内存分配问题:文件名多分配1字节存结束符,避免缓冲区溢出。
  4. 替换fflush(stdin):用while(getchar() != '\n')清理输入缓冲区,符合C标准。

现在你再运行代码,二进制文件里就只会有你写入的学生数据,不会出现奇怪的额外信息了。

内容的提问来源于stack exchange,提问作者Тодор Тодоров

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 05:12:35