C语言中使用fwrite写入二进制文件时为何出现空字节?
解决二进制文件写入多余空字节的问题
嘿,你猜的完全没错!问题就出在那个固定长度的char text[100]数组上——你的结构体my_struct大小是100字节,哪怕你只输入了"holiday"这7个字符,数组里剩下的93个位置都是默认初始化的空字节(也就是十六进制的00),fwrite会把整个结构体的全部内容都写入文件,自然就出现了一堆多余的空字节。
下面给你几个实用的解决方案,按需选择:
方案一:只写入实际输入的字符串内容(最简单的修改)
既然我们只需要保存用户输入的文本,那就不用把整个数组都写进去,只写实际的字符串长度(包括字符串结束符\0)就行。
首先先修正你代码里的两个隐患:
gets函数已经被C标准废弃了,容易造成缓冲区溢出,换成fgets更安全;fflush(stdin)是未定义行为,不同编译器表现不一样,用循环清空输入缓冲区更可靠。
修改后的代码如下:
#include <stdio.h> #include <string.h> struct my_struct { char text[100]; } e; int main() { FILE *file; file = fopen("filename", "ab+"); if (file == NULL) { file = fopen("filename", "wb+"); } printf("Input text: "); // 清空输入缓冲区(替代fflush(stdin)) int c; while ((c = getchar()) != '\n' && c != EOF); // 用fgets读取输入,避免缓冲区溢出 fgets(e.text, sizeof(e.text), stdin); // 去掉fgets读取到的换行符 e.text[strcspn(e.text, "\n")] = '\0'; // 只写入实际的字符串长度(+1是为了保留结束符'\0') fwrite(e.text, strlen(e.text) + 1, 1, file); fclose(file); return 0; }
这样写入文件的就只有holiday\0这8个字节,不会有多余的空字节了。注意读取的时候也要对应,不能再按结构体大小读取,而是要读到\0为止(比如用fgets或者逐字节读取)。
方案二:使用动态分配的字符串(更灵活的变长存储)
如果你的文本长度不固定,用动态分配的字符串会更高效,不会浪费空间。我们可以修改结构体,用指针存储字符串,写入时先保存字符串长度,再保存内容:
#include <stdio.h> #include <string.h> #include <stdlib.h> struct my_struct { char *text; } e; int main() { FILE *file; file = fopen("filename", "ab+"); if (file == NULL) { file = fopen("filename", "wb+"); } printf("Input text: "); // 清空输入缓冲区 int c; while ((c = getchar()) != '\n' && c != EOF); // 先用临时缓冲区读取输入 char buffer[100]; fgets(buffer, sizeof(buffer), stdin); buffer[strcspn(buffer, "\n")] = '\0'; // 分配足够的内存存储字符串 e.text = malloc(strlen(buffer) + 1); if (e.text == NULL) { perror("malloc failed"); fclose(file); return 1; } strcpy(e.text, buffer); // 先写入字符串长度,再写入内容(方便后续读取) size_t str_len = strlen(e.text) + 1; fwrite(&str_len, sizeof(str_len), 1, file); fwrite(e.text, str_len, 1, file); // 释放内存,避免泄漏 free(e.text); fclose(file); return 0; }
这种方式的好处是完全不会浪费空间,每个写入的条目只占用实际需要的字节数。读取的时候需要先读取长度,再分配对应大小的内存,然后读取字符串内容。
额外提醒
- 如果你之后需要读取这些内容,一定要和写入的方式对应:方案一写入的是带
\0的字符串,读取时要读到\0;方案二写入的是长度+内容,读取时要先读长度再读内容。 - 永远不要用
gets,它的安全性极差,fgets是更好的选择。
内容的提问来源于stack exchange,提问作者Lucky
相关产品推荐
相关产品推荐

