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

C程序读取第一个输入后暂停,需按两次回车才能继续

去除TXT文件空行的C程序输入异常及文件打开失败问题

我正在编写一个去除.txt文件中文本间空行的C程序,程序会请求用户输入源文件和目标文件名,但遇到两个问题:

  • 输入源文件名后程序暂停,需按两次回车才会继续请求目标文件名;
  • 程序执行到第一个fopen时终止,if(!source)判定为真,说明源文件名被错误解析。

尝试过多种修复方法均无效:在scanf格式字符串中添加空格忽略前导空白、用fgets替代scanf并手动移除换行符、在第一次scanf后显式刷新stdin缓冲区。且获取文件名的代码与之前3-4次实验完全一致,不清楚问题所在。

代码

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

int main() {
    FILE *source, *destination;
    char source_file_name[256], destination_file_name[] = "output.txt", buffer[1024];

    // 提示用户输入源文件名,读取并存储
    printf("Enter the source file name: "); 
    fgets(buffer, sizeof(buffer), stdin);
    sscanf(buffer, "%s", source_file_name);

    // 提示用户输入目标文件名(默认output.txt)
    printf("\nWhat would you like to name the duplicate file? (default name: output.txt): ");
    fgets(buffer, sizeof(buffer), stdin);
    if(strlen(buffer) > 1) { // 若输入了文件名则使用,否则用默认
        sscanf(buffer, "%s", destination_file_name);
    }
    source = fopen(source_file_name, "r");
    if(!source) {
        perror("The source file was not found.");
        return 1;
    }

    destination = fopen(destination_file_name, "w");
    if(!destination) 
    {
        perror("Could not create the destination file.");
        fclose(source); // 退出前关闭源文件
        return 1;
    }

    while (fgets(buffer, sizeof(buffer), source)) {
        char *p = buffer;
        int blank_space = 1;
        while(*p != '\0') {
            if (!isspace((unsigned char) *p)) {
                blank_space = 0;
                break;
            }
            p++;
        }
        if(!blank_space) {
            fputs(buffer, destination);
        }
    }

    fclose(source);
    fclose(destination);

    return 0;   
}

观察到的行为

输入源文件名并按下回车后,程序不会立即提示输入目标文件名,需再次按下回车才会继续执行。

已尝试的修复方法

  • 在scanf的格式字符串中添加空格以忽略前导空白
  • 用fgets替代scanf并手动移除换行符
  • 在第一次scanf后显式刷新stdin缓冲区

环境信息

  • 操作系统:Windows 11
  • IDE:VS Code

问题根源及修复方案

1. 目标文件名缓冲区溢出(核心问题)

destination_file_name被定义为char destination_file_name[] = "output.txt";,这意味着数组长度固定为11("output.txt"的10个字符加上终止符\0)。当用户输入的目标文件名长度超过10时,sscanf会写入超出数组边界的内容,破坏栈上的其他变量(包括source_file_name),导致源文件名被篡改,最终fopen无法找到文件;同时栈帧损坏也会引发输入时的异常行为(需要按两次回车)。

修复:将destination_file_name改为足够大的固定长度数组:

char destination_file_name[256] = "output.txt";

2. fgets读取的换行符处理问题

fgets会将用户输入的换行符\n一并读入缓冲区,虽然sscanf("%s")会跳过空白字符,但如果要支持带空格的文件名,sscanf("%s")会截断文件名。更稳妥的方式是先移除缓冲区中的换行符,再直接复制文件名:

修复示例:

// 处理源文件名输入
printf("Enter the source file name: "); 
fgets(buffer, sizeof(buffer), stdin);
// 移除换行符
buffer[strcspn(buffer, "\n")] = '\0';
strncpy(source_file_name, buffer, sizeof(source_file_name) - 1);
source_file_name[sizeof(source_file_name)-1] = '\0'; // 确保终止符存在

// 处理目标文件名输入
printf("\nWhat would you like to name the duplicate file? (default name: output.txt): ");
fgets(buffer, sizeof(buffer), stdin);
buffer[strcspn(buffer, "\n")] = '\0';
if(strlen(buffer) > 0) {
    strncpy(destination_file_name, buffer, sizeof(destination_file_name) - 1);
    destination_file_name[sizeof(destination_file_name)-1] = '\0';
}

3. 增加输入校验

添加输入读取后的校验逻辑,确保文件名有效,避免未初始化变量导致fopen失败。


修改后的完整代码

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

int main() {
    FILE *source, *destination;
    char source_file_name[256], destination_file_name[256] = "output.txt", buffer[1024];

    // 处理源文件名输入
    printf("Enter the source file name: "); 
    if (fgets(buffer, sizeof(buffer), stdin) == NULL) {
        perror("Failed to read input");
        return 1;
    }
    // 移除换行符
    buffer[strcspn(buffer, "\n")] = '\0';
    // 复制文件名,避免溢出
    strncpy(source_file_name, buffer, sizeof(source_file_name) - 1);
    source_file_name[sizeof(source_file_name)-1] = '\0';

    // 处理目标文件名输入
    printf("\nWhat would you like to name the duplicate file? (default name: output.txt): ");
    if (fgets(buffer, sizeof(buffer), stdin) == NULL) {
        perror("Failed to read input");
        return 1;
    }
    buffer[strcspn(buffer, "\n")] = '\0';
    if(strlen(buffer) > 0) {
        strncpy(destination_file_name, buffer, sizeof(destination_file_name) - 1);
        destination_file_name[sizeof(destination_file_name)-1] = '\0';
    }

    source = fopen(source_file_name, "r");
    if(!source) {
        perror("The source file was not found.");
        return 1;
    }

    destination = fopen(destination_file_name, "w");
    if(!destination) 
    {
        perror("Could not create the destination file.");
        fclose(source);
        return 1;
    }

    while (fgets(buffer, sizeof(buffer), source)) {
        char *p = buffer;
        int blank_space = 1;
        while(*p != '\0') {
            if (!isspace((unsigned char) *p)) {
                blank_space = 0;
                break;
            }
            p++;
        }
        if(!blank_space) {
            fputs(buffer, destination);
        }
    }

    fclose(source);
    fclose(destination);
    printf("Processing completed successfully.\n");

    return 0;   
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 18:20:39