have logical error, it proceed to addOrder even if it greater than max

53 views Asked by At

my code has logical error i think, if I enter a number greater than max, the error void will show up, but the it still proceed on addOrder. I want to loop it if the user input is invalid it will clear the buffer and the user will input again. Can you please help me?

my code has logical error i think, if I enter a number greater than max, the error void will show up, but the it still proceed on addOrder. I want to loop it if the user input is invalid it will clear the buffer and the user will input again. Can you please help me?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h> 
#include <unistd.h> //for sleep function
//for color text
#define Reset_txt "\033[0m"
#define Red_txt "\033[0;31m"
#define Green_txt "\033[0;32m"

// Global variables
int userChoice;
char productNames[3][50];
double prices[3]; // this arrays used to stores the data price of different orders and prices
double payment = 0;
double userchanges[3];
double userMoney[3];
char Spag[50] = "Spaghetti";
char Pal[50] = "Palabok";
char Chic[50] = "Chicken";
int order = 0;

// Function to display an error message
void error() 
{
printf(Red_txt "Invalid input!\n" Reset_txt);
return;
}

// Function to simulate ordering food
void loadingScreen() 
{
int i;
printf("Loading: ");
for (i = 0; i < 20; ++i) 
{
    printf("*");
    fflush(stdout);// Flush the standard output buffer to ensure the asterisk is visible
    usleep(100000);// Introduce a delay of 100,000 microseconds (0.1 seconds)
}
// Provide a prompt for the user to order their meal
printf(Green_txt "\nOrder Successful!\n" Reset_txt);
}

// Display a loading animation
void orderFood() 
{
int i;
printf("Loading: ");
for (i = 0; i < 20; ++i)
{
    printf("*");
    fflush(stdout);// Flush the standard output buffer to ensure the asterisk is visible
    usleep(100000);// Introduce a delay of 100,000 microseconds (0.1 seconds)
}
// Provide a prompt for the user to order their meal
printf(" \nPlease order your meal.\n");
}

// Function to check if input is a valid number
int isValid(char *input) 
{
// Check if the input is empty or consists of only whitespace
if (input == NULL || strspn(input, " \t\n") == strlen(input))
    return 0;

char *endptr;

// Try to convert the input to a number (integer or floating-point)
strtod(input, &endptr);

// If the conversion reaches the end of the string (no error), it's a valid number
return *endptr == '\0';
}

// Function to get user input within a specified range
int getInp(char *inputType, int max) //max: The maximum allowed value for the input
{
 // Declare an array to store user input and initialize a variable for valid input
char userInp[50];
int valid = 0;

while (!valid) 
{
    printf("%s", inputType); // Display the inputType prompt

    // Read user input using fgets
    if (fgets(userInp, sizeof(userInp), stdin) == NULL) 
    {
        error();
        continue;
    }

    // Remove newline character from user input
    userInp[strcspn(userInp, "\n")] = 0;

    if (isValid(userInp) == 1)   // Check if the input is a valid number
    {
        valid = atoi(userInp); // Convert the valid input to an integer

        if (valid < 0 || valid > max) // Check if the input is within the specified range
        {
            error(); // If not, display an error and continue the loop
            continue;
        } 
        else 
        {
            break; // If valid input is received, break out of the loop
        }
    } 
    else 
    {
        error(); // If the input is not a valid number, display an error and continue the loop
        continue;
    }
}
return valid; // Return the valid user input
}

void menu(int order) 
{
orderFood();//void orderFood calling

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");

// Check if the userChoice is out of range
userChoice = getInp("Please select your order: ", 3); //max value 3 
if (userChoice < 1 || userChoice > 3) 
{
    error();
}

switch (userChoice) 
{
    case 1:
        strcpy(productNames[order], Spag); // Set the product name to Spaghetti
        prices[order] = 150.00;  // Set the price for Spaghetti
        break; // Exit the switch statement
    case 2:
        strcpy(productNames[order], Pal); // Set the product name to Palabok
        prices[order] = 120.00; // Set the price for Palabok
        break; // Exit the switch statement
    case 3:
        strcpy(productNames[order], Chic); // Set the product name to Chicken
        prices[order] = 160.00;  // Set the price for Chicken
        break; // Exit the switch statement
    default:
        // If the user enters an invalid choice
        break; // Exit the switch statement
        error();
        getch();
    system("cls");
        menu(order);
}
AddOrder(); // Proceed to the next step, which is adding the order
}

// Function to ask if the user wants to add another order
void AddOrder() 
{
int addOrder;
order++;
addOrder = getInp("Do you want to add another order? ([1] = Yes | [2] = No): ", 2); //maxvalue 2 
// Check if addOrder is out of range
if (addOrder < 1 || addOrder > 2) 
{
    error(); // will call error if it doesn't meet the condition 
    getch(); // will read any char in keyboard
    system("cls"); //to clear the console
    menu(order); //calling the menu(order) void
} 
else if (addOrder == 1) // if the user input 1 it will proceed to cls and menu(order)
{
    system("cls");
    menu(order);
} 
else // if the user input 2 it will proceed to receipt
{
    loadingScreen();
    getch();
    system("cls");
    receipt();
    
}

}

// Function to display the receipt
void receipt() 
{
// Initialize variables to store the total amount, user changes, and money
double TotalAmount = 0.0;
double Totaluserchanges = 0.0;
double TotalMoney = 0.0;

    printf("==============================\n");
    printf("Receipt: \n");
    printf("==============================\n");
  // Loop through each ordered item
for (int i = 0; i < order; i++) 
{
    printf("Food selected: %s\n", productNames[i], i + 1);//Print the selected food and its index
    printf("Product price: P%.2lf\n", prices[i], i + 1); // Print the price of the selected food
    TotalAmount += prices[i]; // Accumulate the total amount of the order
    TotalMoney += userMoney[i];  Accumulate the total money received
    Totaluserchanges += userchanges[i]; / Accumulate the total change for each order
}
printf("Total amount of product: P%.2lf\n", TotalAmount);

do
{
//the user ask to input money
    printf("Enter the amount of money: ");
    scanf("%lf", &TotalMoney);

    if (TotalMoney < TotalAmount) 
    {
        printf(Red_txt"Insufficient money\n"Reset_txt);//if the totalMoney is lessthan totalAmou
        while(getchar() != '\n'); // Clear the buffer
    } 
    else 
    {
        Totaluserchanges = TotalMoney - TotalAmount; // to get the userchange
        break; // get the total change of user
    }
} while(1);

// Calculate the total user changes by iterating through each order
for (int i = 0; i < order; i++) 
{
    Totaluserchanges += userchanges[i];
}

 // Display the total amounts and changes
printf("==========================\n");
printf("Total amount of product: P%.2lf\n", TotalAmount);//print the total amount of products
printf("Total amount of money: P%.2lf\n", TotalMoney); //total money of the user
printf("Total change: P%.2lf\n", Totaluserchanges); //total change of the user
}

int main() 
{
menu(order);
}
1

There are 1 answers

0
Allan Wind On
  1. First I had to fix some syntax errors (missing comments characters) and as I don't have getch() on my system I changed those to getchar() which you are also using. Also, i + 1 had no associated format string in receipt() and missing function declarations.

  2. In menu() you ask the user to make a choice:

     userChoice = getInp("Please select your order: ", 3);
     if (userChoice < 1 || userChoice > 3)
         error();
    

    but continue along both in the the normal or error case. The intention is for getInp() to only return with valid data so there shouldn't be a need to check it again.

  3. In getInp() you check for our of range with:

            if (valid < 0 || valid > max) {
                error();
                continue;
            } else {
                break;
            }
    

    so we call getInp(..., 3) and with input 4 the valid < 0 || valid > max is true as 4 > 3 yet you do not set valid = 0 so it remains 1 and the incorrect value is returned.

  4. Back in menu() you you evaluate the user choice in a switch but you shouldn't need the default case if the previous worked as expected. The default case starts with a break; so the remaining code never runs so you should either remove it or move the break; till after the other code.

I would add a min argument to getInp() and simplify it's implementation by using sscanf(). Also, display better errors for easier debugging:

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

#define FAST // FST NML
#define INPUT_MAX 50
#define Reset_txt "\033[0m"
#define Red_txt "\033[0;31m"
#define Green_txt "\033[0;32m"

void AddOrder();
void receipt();

// Global variables
int userChoice;
char productNames[3][50];
double prices[3]; // this arrays used to stores the data price of different orders and prices
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(const char *s) {
    printf(Red_txt "%s\n" Reset_txt, s);
    return;
}

// Function to simulate ordering food
void loadingScreen() {
#ifndef FAST
    printf("Loading: ");
    for (int i = 0; i < 20; ++i) {
        printf("*");
        fflush(stdout);// Flush the standard output buffer to ensure the asterisk is visible
        usleep(100000);// Introduce a delay of 100,000 microseconds (0.1 seconds)
    }
    // Provide a prompt for the user to order their meal
#endif
    printf(Green_txt "\nOrder Successful!\n" Reset_txt);
}

// Display a loading animation
void orderFood() {
#ifndef FAST
    int i;
    printf("Loading: ");
    for (int i = 0; i < 20; ++i)
    {
        printf("*");
        fflush(stdout);// Flush the standard output buffer to ensure the asterisk is visible
        usleep(100000);// Introduce a delay of 100,000 microseconds (0.1 seconds)
    }
#endif
    // Provide a prompt for the user to order their meal
    printf("Please order your meal.\n");
}

int getInp(char *prompt, int min, int max) {
    char s[INPUT_MAX];
    printf("%s: ", prompt);
    for(;;) {
        if(!fgets(s, sizeof(s), stdin)) {
            if(feof(stdin))
                exit(1);
            error("Expected a string");
            continue;
        }
        int i;
        int pos;
        if(sscanf(s, "%d%n", &i, &pos) != 1) {
            error("Expected a number");
            continue;
        }
        if(s[pos] != '\n') {
            error("Expected a number only; too much data");
            continue;
        }
        if(i < min || i > max) {
            error("Expected a number given range");
            continue;
        }
        return i;
    }
}

void menu(int order) {
    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");
    userChoice = getInp("Please select your order", 1, 3);
    fflush(stdout);
    switch (userChoice) {
        case 1:
            strcpy(productNames[order], Spag); // Set the product name to Spaghetti
            prices[order] = 150.00;  // Set the price for Spaghetti
            break;
        case 2:
            strcpy(productNames[order], Pal); // Set the product name to Palabok
            prices[order] = 120.00; // Set the price for Palabok
            break;
        case 3:
            strcpy(productNames[order], Chic); // Set the product name to Chicken
            prices[order] = 160.00;  // Set the price for Chicken
            break;
    }
    AddOrder(); // Proceed to the next step, which is adding the order
}

// Function to ask if the user wants to add another order
void AddOrder() {
    int addOrder;
    order++;
    addOrder = getInp("Do you want to add another order? ([1] = Yes | [2] = No)", 1, 2);
    if (addOrder == 1) {
        system("cls");
        menu(order);
    } else {
        loadingScreen();
        getchar();
        system("cls");
        receipt();
    }

}

// Function to display the receipt
void receipt() {
    double TotalAmount = 0.0;
    double Totaluserchanges = 0.0;
    double TotalMoney = 0.0;
    printf("==============================\n");
    printf("Receipt: \n");
    printf("==============================\n");
    // Loop through each ordered item
    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];
        TotalMoney += userMoney[i];
        Totaluserchanges += userchanges[i];
    }
    printf("Total amount of product: P%.2lf\n", TotalAmount);

    for(;;) {
        printf("Enter the amount of money: ");
        scanf("%lf", &TotalMoney);

        if (TotalMoney < TotalAmount) {
            printf(Red_txt"Insufficient money\n"Reset_txt);
            while(getchar() != '\n');
        } else {
            Totaluserchanges = TotalMoney - TotalAmount; // to get the userchange
            break;
        }
    }
    for (int i = 0; i < order; i++) {
        Totaluserchanges += userchanges[i];
    }
    printf("==========================\n");
    printf("Total amount of product: P%.2lf\n", TotalAmount);//print the total amount of products
    printf("Total amount of money: P%.2lf\n", TotalMoney); //total money of the user
    printf("Total change: P%.2lf\n", Totaluserchanges); //total change of the user
}

int main() {
    menu(order);
}

and example partial run:

Please order your meal.
|=======================|
|          Menu         |
|=======================|
|         Prices:       |
| [1] Spaghetti: 150.00 |
| [2] Palabok:   120.00 |
| [3] Chicken:   160.00 |
|=======================|
Please select your order: 
Expected a number
0a
Expected a number only; too much data
0
Expected a number given range
4
Expected a number given range
1
Do you want to add another order? ([1] = Yes | [2] = No): 2

Order Successful!

There are many other issues like:

  • Define some structs to hold your menu and order etc.
  • Eliminating global variables
  • Write a clear() function instead of system("cls")
  • Use const when possible
  • Let the compiler derive sizes of arrays for strings (const char Spag[] = "Spaghetti";)
  • Eliminate magic numbers in favor of symbolic constants.