使用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; }
关键修复点解释
- 修正
fwrite参数:每个字段的size参数必须是该字段类型的大小,比如int用sizeof(int),char用sizeof(char),这样才会准确写入对应长度的数据,不会把堆里的垃圾带进去。 - 初始化所有变量:给
numberOfStudents赋值,并且先输入学生的信息(你之前的代码完全没给student数组的成员赋值,直接读取strlen是读随机内存)。 - 修复内存分配问题:文件名多分配1字节存结束符,避免缓冲区溢出。
- 替换
fflush(stdin):用while(getchar() != '\n')清理输入缓冲区,符合C标准。
现在你再运行代码,二进制文件里就只会有你写入的学生数据,不会出现奇怪的额外信息了。
内容的提问来源于stack exchange,提问作者Тодор Тодоров
相关产品推荐
相关产品推荐

