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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 21:20:55