C语言点餐程序逻辑错误修复请求:输入超范围仍执行AddOrder
修复C语言点餐程序的输入验证与缓冲区清空问题
问题说明
你的点餐程序存在两个核心问题:输入无效时程序仍会执行后续流程,且输入缓冲区未正确清空导致后续输入异常。以下是修复后的完整代码及关键修改说明。
修复后的完整代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <unistd.h> // 用于sleep函数 // 彩色文本宏定义 #define Reset_txt "\033[0m" #define Red_txt "\033[0;31m" #define Green_txt "\033[0;32m" // 全局变量 int userChoice; char productNames[3][50]; double prices[3]; // 存储不同订单的价格数据 double payment = 0; double userchanges[3]; double userMoney[3]; char Spag[50] = "Spaghetti"; char Pal[50] = "Palabok"; char Chic[50] = "Chicken"; int order = 0; // 显示错误信息 void error() { printf(Red_txt "Invalid input!\n" Reset_txt); } // 模拟下单成功的加载动画 void loadingScreen() { int i; printf("Loading: "); for (i = 0; i < 20; ++i) { printf("*"); fflush(stdout); // 刷新输出缓冲区,确保星号即时显示 usleep(100000); // 延迟0.1秒 } printf(Green_txt "\nOrder Successful!\n" Reset_txt); } // 显示点餐引导的加载动画 void orderFood() { int i; printf("Loading: "); for (i = 0; i < 20; ++i) { printf("*"); fflush(stdout); // 刷新输出缓冲区 usleep(100000); // 延迟0.1秒 } printf(" \nPlease order your meal.\n"); } // 检查输入是否为有效数字 int isValid(char *input) { // 检查输入是否为空或仅含空白字符 if (input == NULL || strspn(input, " \t\n") == strlen(input)) return 0; char *endptr; // 尝试转换为数字(整数或浮点数) strtod(input, &endptr); // 若转换到字符串末尾则为有效数字 return *endptr == '\0'; } // 获取指定范围内的用户输入 int getInp(char *inputType, int max) // max: 允许的最大输入值 { char userInp[50]; int valid = 0; while (!valid) { printf("%s", inputType); // 读取用户输入 if (fgets(userInp, sizeof(userInp), stdin) == NULL) { error(); continue; } // 移除换行符 userInp[strcspn(userInp, "\n")] = 0; if (isValid(userInp)) { valid = atoi(userInp); if (valid < 1 || valid > max) // 修正范围:输入从1开始而非0 { error(); continue; } else { break; } } else { error(); continue; } } return valid; } void menu(int currentOrder) { orderFood(); printf("|=======================|\n"); printf("| Menu |\n"); printf("|=======================|\n"); printf("| Prices: |\n"); printf("| [1] Spaghetti: 150.00 |\n"); printf("| [2] Palabok: 120.00 |\n"); printf("| [3] Chicken: 160.00 |\n"); printf("|=======================|\n"); // getInp已确保输入在1-3范围内,无需二次检查 userChoice = getInp("Please select your order: ", 3); switch (userChoice) { case 1: strcpy(productNames[currentOrder], Spag); prices[currentOrder] = 150.00; break; case 2: strcpy(productNames[currentOrder], Pal); prices[currentOrder] = 120.00; break; case 3: strcpy(productNames[currentOrder], Chic); prices[currentOrder] = 160.00; break; } AddOrder(); } // 询问用户是否添加新订单 void AddOrder() { int addOrder; addOrder = getInp("Do you want to add another order? ([1] = Yes | [2] = No): ", 2); if (addOrder == 1) { order++; // 确认添加新订单后再递增计数 system("cls"); // Windows清屏,Linux/macOS请改为system("clear") menu(order); } else { loadingScreen(); // 清空缓冲区避免影响后续输入 while(getchar() != '\n'); system("cls"); receipt(); } } // 显示收据 void receipt() { double TotalAmount = 0.0; double Totaluserchanges = 0.0; double TotalMoney = 0.0; printf("==============================\n"); printf("Receipt: \n"); printf("==============================\n"); for (int i = 0; i <= order; i++) { printf("Food selected: %s\n", productNames[i]); printf("Product price: P%.2lf\n", prices[i]); TotalAmount += prices[i]; } printf("Total amount of product: P%.2lf\n", TotalAmount); do { printf("Enter the amount of money: "); // 读取金额后清空缓冲区 if (scanf("%lf", &TotalMoney) != 1) { error(); while(getchar() != '\n'); continue; } if (TotalMoney < TotalAmount) { printf(Red_txt"Insufficient money\n"Reset_txt); while(getchar() != '\n'); } else { Totaluserchanges = TotalMoney - TotalAmount; break; } } while(1); printf("==========================\n"); printf("Total amount of product: P%.2lf\n", TotalAmount); printf("Total amount of money: P%.2lf\n", TotalMoney); printf("Total change: P%.2lf\n", Totaluserchanges); } int main() { menu(order); return 0; }
关键修改点
- 修正
getInp范围检查:将输入下限从0改为1,匹配菜单选项从1开始的逻辑,确保无效输入会被拦截并重新要求输入。 - 移除冗余检查代码:删除
menu和AddOrder中对getInp返回值的二次范围验证,因为getInp已经确保输入在有效范围内。 - 调整订单计数时机:把
order递增操作从AddOrder开头移到用户选择"添加新订单"之后,避免用户选择"不添加"时产生空订单计数。 - 完善缓冲区清空逻辑:在
loadingScreen结束后、scanf读写前后都添加缓冲区清空代码,彻底解决残留字符干扰后续输入的问题。 - 修复收据统计范围:将收据循环条件从
i < order改为i <= order,确保最后一个订单能被正确统计;同时删除重复的Totaluserchanges累加代码,避免计算错误。 - 替换非标准函数:去掉非标准的
getch(),改用标准库的getchar()处理输入等待,提升程序跨平台兼容性。
内容的提问来源于stack exchange,提问作者zeraus
相关产品推荐
相关产品推荐

