Thread: C Primer Plus Exercise ch7.08

  1. #1
    Registered User
    Join Date
    May 2016
    Posts
    4

    C Primer Plus Exercise ch7.08

    Hi, I got stuck at the 8th exercise of ch7 in the book C Primer Plus. The requirement is (it is a follow up of exercise No7, so I will paste both No7 and No8 below):

    7. Write a program that requests the hours worked in a week and then prints the gross pay,the taxes, and the net pay. Assume the following:
    a. Basic pay rate = $10.00/hr
    b. Overtime (in excess of 40 hours) = time and a half
    c. Tax rate: #15% of the first $300
    20% of the next $150
    25% of the rest

    Use #define constants, and don’t worry if the example does not conform to currenttax law.

    8. Modify assumption a. in exercise 7 so that the program presents a menu of pay ratesfrom which to choose. Use a
    switch to select the pay rate. The beginning of a runshould look something like this:
    ************************************************** ***************
    Enter the number corresponding to the desired pay rate or action:
    1) $8.75/hr 2) $9.33/hr
    3) $10.00/hr 4) $11.20/hr
    5) quit
    ************************************************** ***************
    If choices 1 through 4 are selected, the program should request the hours worked. Theprogram should recycle until 5 is entered. If something other than choices 1 through 5is entered, the program should remind the user what the proper choices are and thenrecycle. Use #defined constants for the various earning rates and tax rates.




    And this is my code:
    Code:
    #include <stdio.h>
    #define RATE1 8.75
    #define RATE2 9.33
    #define RATE3 10.00
    #define RATE4 11.20
    #define TAX1 0.15
    #define TAX2 0.2
    #define TAX3 0.25
    #define TAX1_LEVEL 300
    #define TAX2_LEVEL TAX1_LEVEL + 150
    #define TAX1_FULL TAX1 * TAX1_LEVEL
    #define TAX2_FULL TAX2 * 150 + TAX1_FULL
    int main(void)
    {
        float rate, hours, gross, tax, net;
        int m, choice;
        // This is the input menu.
        printf("*****************************************************************\n");
        printf("Enter the number corresponding to the desired pay rate or action:\n");
        printf("1) $8.75/hr                           2) $8.33/hr\n");
        printf("3) $10.00/hr                          4) $11.20/hr\n");
        printf("5) quit\n");
        printf("*****************************************************************\n");
        
        m = scanf("%d", &choice);
        
        while(m != 1)
        {
            printf("Please input an integer between 1 to 5.\n");
            m = scanf("%d", &choice);
        }
        
        while(m == 1)
        {
            switch (choice)
            {
                case 1 :    rate = RATE1;
                            break;
                case 2 :    rate = RATE2;
                            break;
                case 3 :    rate = RATE3;
                            break;
                case 4 :    rate = RATE4;
                            break;
                case 5 :    goto quit; //quit the whole programme
                default:    printf("Please input a number from 1 to 5 to choose!\n");
                            goto enteragain; //jump over the calculations to enter rate again        
            }
            printf("You've chosen the rate number%d: %.2f.\n", choice, rate);    
            
            //enter the worked hours
            printf("\nNow enter the hours worked in a week: \n");
            scanf("%f", &hours);
            
            //determine the gross pay
            if (hours <= 40)
                gross = rate * hours;
            else
                gross = rate * 40 + 1.5 * rate * (hours - 40);
            
            //determine the tax value
            if (gross <= TAX1_LEVEL)
                tax = gross * TAX1;
            else if (gross <= TAX2_LEVEL)
                tax = TAX1_FULL + (gross - TAX1_LEVEL) * TAX2;
            else
                tax = TAX2_FULL + (gross - TAX2_LEVEL) * TAX3;
            
            //net pay
            net = gross - tax;
            
            //output
            printf("\nThe gross pay is %.2f.\nTaxes : %.2f.\nNet pay is %.2f.\n\n", gross, tax, net);
            
            //enter again
            printf("Please enter your choice again: \n");
            enteragain: m = scanf("%d", &choice);
            while(m != 1)
            {
                printf("Please input an integer between 1 to 5.\n");
                m = scanf("%d", &choice);
            }
        }
            
        quit: printf("Bye.\n");
        
        return 0;
    }
    Compiled and ran. Works fine if I input an integer as required. But if a non-integer value was inputted, I had the "Please input an integer between 1 to 5." running non-stop and I can't type in any other input. Anyone can give me a hint or any suggestion to improve my code?

  2. #2
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    The reason you get an infinite loop if you enter a non-integer is that the scanf function leaves the input in the buffer and keeps seeing it again and again. If the input is garbage you need to clean out the input buffer. And you may as well make you input routine a function.

    The use of goto is generally considered suboptimal. Beginners should really never use it as it can create bad habits. There's pretty much always an alternative.

    You should generally put parentheses around macros definitions that have more than one token. Consider
    Code:
    #define TAX2_LEVEL TAX1_LEVEL + 150
    If this was used like so
    Code:
    x = 10 * TAX2_LEVEL;
    It would pan out as
    Code:
    x = 10 * 300 + 150
    and since multiplication is done first you'd get 3150 where 4500 was expected.
    So it should be defined as
    Code:
    #define TAX2_LEVEL (TAX1_LEVEL + 150)
    Code:
    #include <stdio.h>
    
    // Note that this allows input like 4xyz, returning 4.
    // In general, validating input is quite a chore so you shouldn't get too hung up on it yet.
    // As an exercise you could make the low and high values parameters.
    // You could make a similar function for entering the hours.
    int get_choice(void) {
        int n = 0;
        while (1) {
            printf("Enter a number from 1 to 5: ");
            scanf("%d", &n);
            while (getchar() != '\n')  // eat input buffer up to and incl. newline
                ;
            if (n >= 1 && n <= 5)
                break;
            printf("That wasn't a number from 1 to 5!\n");
        }
        return n;
    }
    
    int main(void) {
        while (1) {
            int done = 0;
    
            print_menu();  // could make this a function ... or not
    
            switch (get_choice()) {
            //...
            case 5:
                done = 1;
                break;
            //...
            // Don't need "enter again" part since get_choice validates the choice
            }
    
            if (done)
                break;
    
            //...
        }
    
        return 0;
    }

  3. #3
    Registered User
    Join Date
    May 2016
    Posts
    4
    Once again thanks very much for the solution and explanation. I've finish the modification based on your suggestion and it works well. The using of getchar() really make a difference. But I still have one question about this particular code: shouldn't I hit the ENTER key twice for the input so one ENTER for the sending of the scanf() data and another ENTER for the getchar()? When I ran the code I only need to hit Enter once.Sorry to bother you on these perhaps I shouldn't hung up on the input too much as you advised..


    Quote Originally Posted by algorism View Post
    The reason you get an infinite loop if you enter a non-integer is that the scanf function leaves the input in the buffer and keeps seeing it again and again. If the input is garbage you need to clean out the input buffer. And you may as well make you input routine a function.

    The use of goto is generally considered suboptimal. Beginners should really never use it as it can create bad habits. There's pretty much always an alternative.

    You should generally put parentheses around macros definitions that have more than one token. Consider
    Code:
    #define TAX2_LEVEL TAX1_LEVEL + 150
    If this was used like so
    Code:
    x = 10 * TAX2_LEVEL;
    It would pan out as
    Code:
    x = 10 * 300 + 150
    and since multiplication is done first you'd get 3150 where 4500 was expected.
    So it should be defined as
    Code:
    #define TAX2_LEVEL (TAX1_LEVEL + 150)
    Code:
    #include <stdio.h>
    
    // Note that this allows input like 4xyz, returning 4.
    // In general, validating input is quite a chore so you shouldn't get too hung up on it yet.
    // As an exercise you could make the low and high values parameters.
    // You could make a similar function for entering the hours.
    int get_choice(void) {
        int n = 0;
        while (1) {
            printf("Enter a number from 1 to 5: ");
            scanf("%d", &n);
            while (getchar() != '\n')  // eat input buffer up to and incl. newline
                ;
            if (n >= 1 && n <= 5)
                break;
            printf("That wasn't a number from 1 to 5!\n");
        }
        return n;
    }
    
    int main(void) {
        while (1) {
            int done = 0;
    
            print_menu();  // could make this a function ... or not
    
            switch (get_choice()) {
            //...
            case 5:
                done = 1;
                break;
            //...
            // Don't need "enter again" part since get_choice validates the choice
            }
    
            if (done)
                break;
    
            //...
        }
    
        return 0;
    }

  4. #4
    Registered User ssharish2005's Avatar
    Join Date
    Sep 2005
    Location
    Cambridge, UK
    Posts
    1,732
    You need a function something like this

    Code:
    void clear_stdin(void).
    {
        int ch =getchar();
        while( ch != '\n' && ch != '\0' ).
            ch = getchar();
    }
    This clears the input buffer when the scanf leaves the input buffer in bad state. Or in this case garbage values.
    Life is like riding a bicycle. To keep your balance you must keep moving - Einstein

  5. #5
    Registered User rstanley's Avatar
    Join Date
    Jun 2014
    Location
    New York, NY
    Posts
    1,106
    Quote Originally Posted by ssharish2005 View Post
    You need a function something like this

    Code:
    void clear_stdin(void).
    {
        int ch =getchar();
        while( ch != '\n' && ch != '\0' ).
            ch = getchar();
    }
    This clears the input buffer when the scanf leaves the input buffer in bad state. Or in this case garbage values.
    You have two extraneous periods, '.', on the end of the line on both lines 1, and 4. This should have generated errors when compiling.

    Please turn on and turn up your warning levels on your compiler, and test your code before posting.



    Edit: Actually, your version of clear_stdin() does not even work? Why? ;^)

    There are enough examples of this code on the net to show you why not.
    Last edited by rstanley; 05-17-2016 at 11:20 AM. Reason: Added comments

  6. #6
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    Quote Originally Posted by llnnttss View Post
    Once again thanks very much for the solution and explanation. I've finish the modification based on your suggestion and it works well. The using of getchar() really make a difference. But I still have one question about this particular code: shouldn't I hit the ENTER key twice for the input so one ENTER for the sending of the scanf() data and another ENTER for the getchar()? When I ran the code I only need to hit Enter once.Sorry to bother you on these perhaps I shouldn't hung up on the input too much as you advised..
    The input, being line buffered, is not acted on at all until you hit ENTER, which puts a newline character in the stream. The scanf, with the %d or %f format specifier, only reads what it needs to get a number. It leaves extra characters, including the newline, behind in the stream (it actually reads it and then pushes it back using something like the ungetc function). One of my comments was that if you entered 4xyz followed by a newline, the xyz as well as the newline would be left in the stream. If you entered 4.1.2 and read it with %f it would read 4.1 and leave the .2 (and newline) behind.

  7. #7
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    Quote Originally Posted by ssharish2005 View Post
    You need a function something like this

    Code:
    void clear_stdin(void).
    {
        int ch =getchar();
        while( ch != '\n' && ch != '\0' ).
            ch = getchar();
    }
    This clears the input buffer when the scanf leaves the input buffer in bad state. Or in this case garbage values.
    Presumably you mean ch != EOF, not ch != '\0'. The former is a good idea. I forgot to put that into my suggested code.
    Code:
    int c;
    while ((c = getchar()) != '\n' && c != EOF)
        ;

  8. #8
    Registered User ssharish2005's Avatar
    Join Date
    Sep 2005
    Location
    Cambridge, UK
    Posts
    1,732
    I have no idea why the periods are in place. I did compile and got it working before I posted it. It probaby something to do with the editor which happened to vim..

    I get the point with the EOF and also using the getchar in within the while loop.
    Life is like riding a bicycle. To keep your balance you must keep moving - Einstein

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. C Primer Plus Exercise ch7.02
    By llnnttss in forum C Programming
    Replies: 3
    Last Post: 05-15-2016, 04:36 PM
  2. C++ Primer exercise 16.47
    By frank67 in forum C++ Programming
    Replies: 10
    Last Post: 10-26-2015, 05:36 AM
  3. c++ primer exercise 16.12
    By frank67 in forum C++ Programming
    Replies: 18
    Last Post: 09-30-2015, 03:32 PM
  4. c++ primer exercise 15.31
    By frank67 in forum C++ Programming
    Replies: 10
    Last Post: 09-23-2015, 09:38 AM
  5. c++ primer exercise 15.26
    By frank67 in forum C++ Programming
    Replies: 2
    Last Post: 09-18-2015, 09:34 AM

Tags for this Thread