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

C语言中使用fwrite写入二进制文件时为何出现空字节?

解决二进制文件写入多余空字节的问题

嘿,你猜的完全没错!问题就出在那个固定长度的char text[100]数组上——你的结构体my_struct大小是100字节,哪怕你只输入了"holiday"这7个字符,数组里剩下的93个位置都是默认初始化的空字节(也就是十六进制的00),fwrite会把整个结构体的全部内容都写入文件,自然就出现了一堆多余的空字节。

下面给你几个实用的解决方案,按需选择:

方案一:只写入实际输入的字符串内容(最简单的修改)

既然我们只需要保存用户输入的文本,那就不用把整个数组都写进去,只写实际的字符串长度(包括字符串结束符\0)就行。

首先先修正你代码里的两个隐患:

  1. gets函数已经被C标准废弃了,容易造成缓冲区溢出,换成fgets更安全;
  2. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:40:41