简体   繁体   中英

How to get the operations to work without the use of global variables in C

The user will enter an integer corresponding with each action. When an action is entered, perform the associated functionality (see below). These actions will operate on the users current balance, changing it's value. Note once each action is completed, the main menu is presented again (loops), until the user enters 4 on the main menu to quit.

,,Can someone help with getting the withdraw, and deposit operations to work and then show on the current balance after with the new balance: without using global variables, and in C:

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

int checkBalance(int balance);
int withdraw(int balance, int amountWithdraw);
int deposit(int balance, int amountDeposit);
int main()
{
    int balance = 10;
    int menuChoice;

    do{
        printf("1) Withdraw\n");
        printf("2) Deposit\n");
        printf("3) CheckBalance\n");
        printf("4) Quit\n");
        printf("Select an option: ");
        scanf("%d", &menuChoice);

    switch(menuChoice){
        case(1):
            checkBalance(balance);
            withdraw(balance, withdraw);
            checkBalance(balance);
            break;
        case(2):
            checkBalance(balance);
            deposit(balance, deposit);
            checkBalance(balance);
            break;
        case(3):
            checkBalance(balance);
            printf("\n");
        }
        }while(menuChoice!=4);
            checkBalance(balance);
            return 0;

}

int withdraw(int balance, int amountWithdraw){
    //int amountWithdraw;
    balance = 10;
    printf("What is the amount of your withdraw: \n");
    scanf("%d", &amountWithdraw);
    balance - amountWithdraw;
}

int deposit(int balance, int amountDeposit){
    //int amountDeposit;
    balance = 10;
    printf("What is the amount of ur deposit: \n");
    scanf("%d", &amountDeposit);
    balance + amountDeposit;
}

int checkBalance(int balance){
    balance = 10;
    printf("Your current balance is: %d\n", balance);
}

Tom, it is apparent that you are struggling with how to determine what the individual pieces of your code need to do, and how to organize them. That's normal, that's part of learning. What I've noticed over the years is that generally results from picking up the keyboard, before you have finished working out the logic with paper and pencil.

The key to successfully completing any journey, is knowing where you are going before you step out of the door. Programming any individual program is just another journey.

From what I can tell, you have four functions you need to put together to complete a simple integer bank balance program. Before you pick up the keyboard, you should know what you want each to do. Start with your account balance, balance . That will be declared in main() . Any of your functions that need the balance will need to have balance passed as a parameter. In C, all parameters are passed-by-value meaning the function receives its very own copy of the variable. Any operations on that variable will be lost when the function returns.

In order to make any modifications to the parameter available back to calling function ( main() here), you need to return the modified value. That way with balance , the account balance back in main() can be updated with any changes. (you can also pass a pointer to the variable and update the value at that address, which you will see in the getint() function, but for your case, just return the changed values)

When thinking about what your functions should do, that also means choosing a proper return type for the function. Any function that can succeed or fail (like an input function) must have a way of indicating success/failure to the caller. Any function that modifies and returns a value, needs to return the proper type. If the function has no impact on the continued operation of your code (like a simple function that prints out data), then void is the proper choice.

When looking at the operation of your functions, your checkBalance() function does nothing but print the user's balance. It doesn't return anything, so void type is fine. The remaining two functions deposit() and withdraw() both modify the balanc passed as a parameter, so they must both return the updated bank balance. In your cod above, int is the correct return type.

Lastly, you want to separate your program interface from the program implementation. Your program interface is the part that interacts with the user, presents prompts and takes input and outputs data. Your program implementation is the processing of program data, the calculations, etc.. What that means is for your deposit() or withdraw() function, you don't want to generate output there. Consider instead of displaying text on a terminal, your are updating a GUI form in windows of X. You don't want deposit() or withdraw() spewing a bunch of text to stdout if the balance is supposed to be displayed in a graphical text-box.

There will always be some overlap and some function will always need to be re-written, but to the greatest amount possible, try and keep the interface and implementation separate. That way it doesn't matter where deposit() or return() are called. If they simply return the updated balance, they will work in any environment.

After some pencil and paper time, all checkBalance() needs to do is output the current balance taken as a parameter. It doesn't modify anything so a void type is used. withdraw() needs a check to ensure that balance > amountWithdraw before reducing the account by amountWithdraw . With deposit() , you simply add amountDeposit to the current balance and return the updated amount. With those changes, your functions, cleaned of interface to a reasonable extent could be:

int withdraw (int balance, int amountWithdraw)
{
    if (balance > amountWithdraw)                   /* validate money available */
        return balance - amountWithdraw;            /* return updated balance */
    
    puts ("  error: insuffient funds");             /* otherwise notify user */
    
    return balance;                                 /* return balance unchanged */
}

int deposit(int balance, int amountDeposit) 
{
    return balance + amountDeposit;
}

void checkBalance (int balance)
{
    printf ("\nYour current balance is: %d\n", balance);
}

If you note above, there isn't any user-input associated with the functions. You handle all input to obtain amountDeposit or amountWithdraw before the functions are called.

Now, you have chosen scanf() for your input. Regardless what input function you are using, you cannot use it correctly unless you check the return to determine whether the input succeeded or failed. If you fail to check the return and blindly use the variable, you risk invoking Undefined Behavior where the input failed. (such as the user slipping an pressing 'r' instead of '4' -- which currently sends your program of into an infinite loop). While you can use scanf() it provides a fragile input routine (unless you properly empty stdin after each input).

The recommended way to take input in C is reading a line-at-a-time using the functions fgets() or POSIX getline() to read the input into a sufficiently sized character array for fgets() ( getline() can automatically allocate storage for you). That way regardless of whether the input is correct or not, the entire line has been consumed and any invalid characters are not left unread in stdin just waiting to bite you on your next attempt. To use scanf() by itself, you must manually empty stdin after each call (unless scanf() returned EOF ). You can do that with a simple helper function, eg

void empty_stdin (void)
{
    int c = getchar();                              /* read 1st char from stdin */
    
    while (c != '\n' && c != EOF)                   /* if not \n or EOF */
        c = getchar();                              /* repeat until it is */
}

Since you are only reading integer values in your code, it would be nice to have a simple function that handled displaying a prompt and then reading and validating the input and calling empty_stdin() when needed. A simple getint() function could be written as:

int getint (int *value, const char *prompt)
{
    for (;;) {                  /* loop continually until good input or canceled */
        int rtn;                                    /* var for return from scanf */
        
        fputs (prompt, stdout);                     /* display prompt */
        rtn = scanf ("%d", value);                  /* read int, save return */
        empty_stdin();                              /* empty input buffer */

        if (rtn == EOF) {                           /* user generated manual EOF */
            puts ("(user canceled input)");
            return 0;
        }
        else if (rtn == 1)                          /* good input, break read loop */
            break;
        
        /* otherwise matching failure */
        fputs ("  error: invalid integer input.\n", stderr);
    }
    
    return 1;       /* return success */
}

That greatly simplifies the body of your code and separates you interface from your implementation. Your main program loop would then need only small changes to handle whatever you were outputting to, be that a form in windows or your terminal. Taking advantage of the helper functions above, you would write you simplified main() as shown in the complete example below:

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

/** account related funcitons */
void checkBalance (int balance);
int withdraw (int balance, int amountWithdraw);
int deposit (int balance, int amountDeposit);

/** helper functions */
void empty_stdin (void);
int getint (int *value, const char *prompt);

int main (void)
{
    int amount = 0,
        balance = 10,
        menuChoice = 0;

    for (;;) {  /* loop continually displaying menu and handling input until quit */
        
        /* use common getint() function to handle all user-input, validate return */
        if (!getint (&menuChoice, "\n  1) Withdraw\n"
                                    "  2) Deposit\n"
                                    "  3) CheckBalance\n"
                                    "  4) Quit\n\n"
                                    "Select an option: ")) {
            puts ("(user canceled input)");
            return 0;
        }
        
        switch (menuChoice) {   /* switch on choice */
            case 1:
                if (!getint (&amount, "\namount to withdraw: "))
                    goto canceled;
                
                balance = withdraw (balance, amount);
                
                checkBalance (balance);
                break;
            case 2:
                if (!getint (&amount, "\namount to deposit: "))
                    goto canceled;
                
                balance = deposit (balance, amount);
                
                checkBalance (balance);
                break;
            case 3:
                checkBalance (balance);
                break;
            case 4:
                goto done;
                break;
            default:
                fputs ("  error: invalid menu selection.\n", stderr);
                break;
        }
        canceled:;
    }
    done:;
    
    checkBalance(balance);
    
    return 0;
}

int withdraw (int balance, int amountWithdraw)
{
    if (balance > amountWithdraw)                   /* validate money available */
        return balance - amountWithdraw;            /* return updated balance */
    
    puts ("  error: insuffient funds");             /* otherwise notify user */
    
    return balance;                                 /* return balance unchanged */
}

int deposit(int balance, int amountDeposit) 
{
    return balance + amountDeposit;
}

void checkBalance (int balance)
{
    printf ("\nYour current balance is: %d\n", balance);
}

void empty_stdin (void)
{
    int c = getchar();                              /* read 1st char from stdin */
    
    while (c != '\n' && c != EOF)                   /* if not \n or EOF */
        c = getchar();                              /* repeat until it is */
}

int getint (int *value, const char *prompt)
{
    for (;;) {                  /* loop continually until good input or canceled */
        int rtn;                                    /* var for return from scanf */
        
        fputs (prompt, stdout);                     /* display prompt */
        rtn = scanf ("%d", value);                  /* read int, save return */
        empty_stdin();                              /* empty input buffer */

        if (rtn == EOF) {                           /* user generated manual EOF */
            puts ("(user canceled input)");
            return 0;
        }
        else if (rtn == 1)                          /* good input, break read loop */
            break;
        
        /* otherwise matching failure */
        fputs ("  error: invalid integer input.\n", stderr);
    }
    
    return 1;       /* return success */
}

Example Use/Output

Any time you write any sort of input routine, go try and break it. You need to try and think of any way a user of your could would input invalid data and make sure that is handled by your code properly. When you find something that doesn't work, or slips by, go fix it and try again. The fact an input routine you wrote breaks isn't a failure, it just shows where additional work is needed. The only failure would come from failing to thoroughly check it. (the user will always, always enter invalid input, and in today's time, may intentionally try and seen a million characters of shellcode as an exploit -- handle it all)

With intentional invalid input below, you would get:

$ ./bin/bankbalance

  1) Withdraw
  2) Deposit
  3) CheckBalance
  4) Quit

Select an option: 3

Your current balance is: 10

  1) Withdraw
  2) Deposit
  3) CheckBalance
  4) Quit

Select an option: I want to Deposit money
  error: invalid integer input.

  1) Withdraw
  2) Deposit
  3) CheckBalance
  4) Quit

Select an option: 2

amount to deposit: 10

Your current balance is: 20

  1) Withdraw
  2) Deposit
  3) CheckBalance
  4) Quit

Select an option: 1

amount to withdraw: 5

Your current balance is: 15

  1) Withdraw
  2) Deposit
  3) CheckBalance
  4) Quit

Select an option: 1

amount to withdraw: 20
  error: insuffient funds

Your current balance is: 15

  1) Withdraw
  2) Deposit
  3) CheckBalance
  4) Quit

Select an option: 9000000 and a lot more
  error: invalid menu selection.

  1) Withdraw
  2) Deposit
  3) CheckBalance
  4) Quit

Select an option: 4

Your current balance is: 15

Look things over and let me know if you have further questions.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM