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

C语言中使用gets()写入文件时出现多余空字符的问题

问题分析与解决

你遇到的核心问题是固定长度结构体的内存填充:你的struct books里的bookName、authorName都是固定50字节的char数组,输入内容长度远小于50时,数组剩余空间会保留内存中的原始值(可能是\0或随机垃圾字节),用fwrite(&b, sizeof(b), 1, fp)直接写入整个结构体时,这些冗余内容会被一并写入文件。

另外你用的fflush(stdin)是未定义行为,C标准仅允许对输出流使用fflush,对输入流调用的结果由编译器决定,不能依赖它清理缓冲区。gets()已被废弃,改用fgets()是正确方向,但你没处理它读入的换行符,这也可能导致额外问题。

解决方案

方案1:按有效数据长度写入(推荐,适合二进制文件)

不直接写入整个结构体,而是分别写入每个字段的有效内容,同时记录每个字符串的长度(方便后续读取)。修改后的代码如下:

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

struct books {
    int id;
    char bookName[50];
    char authorName[50];
    char date[12];
} b;

FILE *fp;

void addBook();
void clearInputBuffer(); // 自定义缓冲区清理函数

int main() {
    int ch;

    while (1) {
        system("cls");
        printf("<== Library Management System ==>\n");
        printf("1. Add Book\n");
        printf("0. Exit\n");
        printf("Enter your choice: ");
        scanf("%d", &ch);
        clearInputBuffer(); // 清理scanf留下的换行符

        switch (ch) {
            case 0:
                exit(0);
            case 1:
                addBook();
                break;
            default:
                printf("Invalid Choice...\n");
        }
        printf("\nPress Any Key to Continue...");
        getch();
    }
    return 0;
}

// 安全清理输入缓冲区的函数
void clearInputBuffer() {
    int c;
    while ((c = getchar()) != '\n' && c != EOF);
}

void addBook() {
    fp = fopen("book.dat", "ab"); // 二进制文件建议用.dat后缀区分
    if (fp == NULL) {
        printf("Error opening file!\n");
        return;
    }

    printf("Enter Book ID: ");
    scanf("%d", &b.id);
    clearInputBuffer(); // 清理缓冲区

    printf("Enter Book Name: ");
    fgets(b.bookName, sizeof(b.bookName), stdin);
    // 去掉fgets读入的换行符
    b.bookName[strcspn(b.bookName, "\n")] = '\0';

    printf("Enter Author Name: ");
    fgets(b.authorName, sizeof(b.authorName), stdin);
    b.authorName[strcspn(b.authorName, "\n")] = '\0';

    // 写入ID(固定字节,方便读取)
    fwrite(&b.id, sizeof(b.id), 1, fp);
    // 写入书名长度+内容
    int nameLen = strlen(b.bookName);
    fwrite(&nameLen, sizeof(int), 1, fp);
    fwrite(b.bookName, sizeof(char), nameLen, fp);
    // 写入作者名长度+内容
    int authorLen = strlen(b.authorName);
    fwrite(&authorLen, sizeof(int), 1, fp);
    fwrite(b.authorName, sizeof(char), authorLen, fp);

    fclose(fp);
    printf("Book Added Successfully.\n");
}

方案2:写入前清空数组(简单但仍有少量冗余)

如果坚持直接写入整个结构体,可以在输入前用memset清空数组,避免垃圾值:

#include<string.h> // 需要引入头文件

void addBook() {
    fp = fopen("book.txt", "ab");
    if (fp == NULL) {
        printf("Error opening file!\n");
        return;
    }

    // 清空结构体数组字段
    memset(b.bookName, 0, sizeof(b.bookName));
    memset(b.authorName, 0, sizeof(b.authorName));
    memset(b.date, 0, sizeof(b.date));

    printf("Enter Book ID: ");
    scanf("%d", &b.id);
    clearInputBuffer();

    printf("Enter Book Name: ");
    fgets(b.bookName, sizeof(b.bookName), stdin);
    b.bookName[strcspn(b.bookName, "\n")] = '\0';

    printf("Enter Author Name: ");
    fgets(b.authorName, sizeof(b.authorName), stdin);
    b.authorName[strcspn(b.authorName, "\n")] = '\0';

    fwrite(&b, sizeof(b), 1, fp);
    fclose(fp);
    printf("Book Added Successfully.\n");
}

这种方式数组剩余部分会被填充为\0,虽比垃圾值好,但仍有冗余字节,适合对文件大小要求不高的场景。

关键注意事项

  • 永远不要用fflush(stdin),用自定义的clearInputBuffer函数清理缓冲区。
  • 替换gets()为fgets(),并处理换行符,避免字符串中包含不必要的换行。
  • 二进制文件建议用.dat这类后缀,和文本文件区分开。
  • 后续读取文件时,必须和写入逻辑对应:比如方案1的读取需要先读ID,再读名字长度,最后读对应长度的字符串。

内容的提问来源于stack exchange,提问作者Krish

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 23:13:20