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
相关产品推荐
相关产品推荐

