0

I need to enter a string and thus included the string.h library, which is needed for the customer name. When I try to run it the item price has a problem. It is supposed to require input from the user and the discount which is already put into the switch type statement is not being called back when the membership type is inputed.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#jeremiahtask4
int getDiscountPercent (char);
 main()
{
    float itemprice,discountedprice,totalpurchase=0.00,totalafterdis=0.00;
    int discount,choice,itemnum=0;
    char membershiptype,additem='Y',name[20];

    printf("\tSuria Supermarket\n");
    printf("\nEnter customer name:");
    scanf("%s",&name);
    printf("\nEnter membership type:");
    reenter:
    scanf("%c\n",&membershiptype);

    do{
    discount=getDiscountPercent(membershiptype);
    if (discount==1)
    goto reenter;
    itemnum++;
    printf("\nItem %d",itemnum);
    printf("\nEnter item price:");
    scanf("%f",&itemprice);
    discountedprice=itemprice*(100-discount)/100.00;
    printf("\n\nDiscount(%%):%d",discount);
    printf("\nDiscounted price:%.2f\n",discountedprice);


    printf("\n\nAdd items (Y/N):");
    fflush(stdin);
    scanf("%c",&additem);
    totalpurchase=totalpurchase+itemprice;
    totalafterdis=totalafterdis+discountedprice;
    }
    while(additem=='Y'||additem=='y');


    printf("\n\t*** Purchase Details ***");
    printf("Customer Name:%s",name);
    printf("\nNumber of items is:%d",itemnum);
    printf("\nTotal purchase:%.2f",totalpurchase);
    printf("\nAmount to pay:%.2f",totalafterdis);

}
int getDiscountPercent(char membershiptype)
  {
    //float itemprice,discountedprice,totalpurchase=0.00,totalafterdis=0.00;
    int discount,choice,itemnum=0;
    //char membershiptype,additem='Y';

      switch(membershiptype)
      {
      case 'p':case 'P':discount=30;break;
      case 'g':case 'G':discount=20;break;
      case 's':case 'S':discount=10;break;
      case 'x':case 'X':discount=0;break;
      default: ;discount =-1;
      }
  return discount;
}
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
Joel Matts
  • 13
  • 3
  • 1
    `scanf("%c\n",&membershiptype);` A trailing `\n` is likely not what you want. Remove it. See: [scanf and newlines in c](https://stackoverflow.com/questions/41767371/scanf-and-newlines-in-c). Also, `%c` will match any character including the trailing new line char from the previous input line. Change those to be `" %c"`, that is, space before `c`. See [scanf Getting Skipped](https://stackoverflow.com/questions/14484431/scanf-getting-skipped) – kaylum Sep 23 '22 at 01:50
  • 1
    And read all the posts recommending the use of `fgets()` for ALL user-input instead of `scanf()` which is full of pitfalls for the new C programmer. If you need to convert the digits in a string to a number after reading from the user, use `sscanf()` instead. If you read a string into `buffer` and need to trim the `'\n'` from the end, use `buffer[strcspn (buffer, "\n")] = 0;` to overwrite the `'\n'` with `0`. – David C. Rankin Sep 23 '22 at 01:59
  • Additionally, you can make `membershiptype` an array of `char` (e.g. `char membershiptype[16];`) and then `switch(membershiptype[0])` or equivalently `switch (*membershiptype)` -- up to you. This allows you to read it with `fgets()` and then just access the 1st character as needed. – David C. Rankin Sep 23 '22 at 02:03
  • Why compare `if (discount==1)` and then have `default: ;discount =-1;` in your switch. That's off-by-2. (if you space your code a little more, it will be easier to spot) – David C. Rankin Sep 23 '22 at 02:13
  • Hey glad to hear about making the membershiptype into an array. It's another perspective that i haven't thought about but the assignment requires the membership type to be like that but we need to add an array in to the code in coming tasks. So thanks again for the help. – Joel Matts Sep 24 '22 at 03:06

1 Answers1

1

You have two primary problems as discussed in the comments. When you use scanf("%s",&name); the '\n' generated by the user pressing Enter is left in the input stream (stdin) unread. On your next call to scanf("%c\n",&membershiptype); the '\n' is read and taken as your input. Further including '\n' in "%c\n" does no good. In fact '\n' is just considered whitespace by scanf, just like a space, or tab. Further name is already a pointer, so you do not include the '&' before it with scanf(). Further, you cannot use "%s" without provide a field-width modifier to protect your array bounds and prevent buffer overrun. Using "%s" without a field width is no safer than using gets(). See Why gets() is so dangerous it should never be used!

When using scanf() the "%c", "%[ ]" and "%n" are the only conversions that do NOT discard leading whitespace. When trying to read membershiptype you should simply include a space, e.g. " %c" which will cause scanf() to read and discard any amount of whitespace before the first character.

(these details for scanf() conversions are why all user input should be done with fgets() into an adequately sized character array (buffer) which avoids all of the pitfalls with scanf())

The next major problem is your comparison of if (discount==1) when you actually return -1 from your function. Your comparison can never test true for that reason. Looking at your code it is incredibly difficult to spot because you have no space in your code. Open it up a bit, add a little more whitespace which will make your code much easier to read, for others, as well as yourself.

Using fgets() for all user input eliminates all of the pitfalls with scanf(). If you need to convert digits in input into numbers, you can use sscanf() with the buffer filled by fgets(). Regardless what you use to read input or how you convert it, you cannot do it correctly unless you check the return of the function you use to determine if the input (or conversion) succeeded or failed.

Additionally, always compile with warnings enabled, and do not accept code until it compiles without warning. To enable warnings add -Wall -Wextra -pedantic to your gcc/clang compile string (also consider adding -Wshadow to warn on shadowed variables). For VS (cl.exe on windows), use /W3. Add -Werror to have the compiler treat warnings as errors. All other compilers will have similar options. Read and understand each warning -- then go fix it. The warnings will identify any problems, and the exact line on which they occur.

Putting the advise altogether, you could do something like the following to fix the problems in your code:

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

#define MEMBSZ 16   /* if you need a constant, #define one (or more) */
#define NAMESZ 64   /*      (don't skimp on buffer size)             */
#define BUFFSZ NAMESZ * 2

int getDiscountPercent (char);

int main (void)
{
    float itemprice,
          discountedprice,
          totalpurchase=0.00,
          totalafterdis=0.00;
    int discount,
        itemnum = 0;
    char  membershiptype[MEMBSZ],
          additem='Y',
          name[NAMESZ],
          buffer[BUFFSZ];

    /* no conversion in output, printf() not needed */
    fputs ("\tSuria Supermarket\n"
           "\nEnter customer name: ", stdout);
    
    /* validate EVERY input */
    if (!fgets (name, NAMESZ, stdin)) {
        puts ("(user canceled input)");
        return 0;
    }
    name[strcspn (name, "\n")] = 0;       /* trim trailing '\n' from name */
    
    fputs ("\nEnter membership type: ", stdout);
    
    reenter:
    if (!fgets (membershiptype, MEMBSZ, stdin)) {
        puts ("(user canceled input)");
        return 0;
    }

    do {
        discount = getDiscountPercent (*membershiptype);
        if (discount == -1)
            goto reenter;
        
        itemnum++;
        
        /* you only need 1 printf() (or puts or fputs)
         * for any continual block of output.
         */
        printf ("\nItem %d\nEnter item price : ", itemnum);
        
        if (!fgets (buffer, BUFFSZ, stdin) || 
            sscanf (buffer, "%f", &itemprice) != 1) {
            fputs ("error: user canceled or invalid float.\n", stderr);
            goto reenter;
        }
        
        discountedprice = itemprice * (100 - discount) / 100.00;
        printf("     Discount(%%) : %d\n"
               "Discounted price : %.2f\n", discount, discountedprice);
    
    
        fputs ("\nAdd items (Y/N): ", stdout);
        if (!fgets (buffer, BUFFSZ, stdin)) {
            fputs ("(user canceled input)", stderr);
            goto reenter;
        }
        additem = *buffer;    /* assign 1st char from buffer */
        
        totalpurchase = totalpurchase + itemprice;
        totalafterdis = totalafterdis + discountedprice;
    }
    while (additem=='Y'||additem=='y');

    /* one output function is all that is needed */
    printf ("\n\t*** Purchase Details ***\n\n"
            "  Customer Name      : %s\n"
            "  Number of items is : %d\n"
            "  Total purchase     : %.2f\n"
            "  Amount to pay      : %.2f\n",
            name, itemnum, totalpurchase, totalafterdis);

}

int getDiscountPercent (char membershiptype)
{
    int discount;

    switch(membershiptype)
    {
      case 'p': case 'P': discount = 30; break;
      case 'g': case 'G': discount = 20; break;
      case 's': case 'S': discount = 10; break;
      case 'x': case 'X': discount =  0; break;
      default: discount = -1;
    }
    return discount;
}

(note: additional comments regarding other improvements made are included in the code above)

Example Use/Output

Now your code will allow entry of items and produce the output you desire, e.g.

$ ./bin/grocerystore
        Suria Supermarket

Enter customer name: Mickey Mouse

Enter membership type: g

Item 1
Enter item price : 10
     Discount(%) : 20
Discounted price : 8.00

Add items (Y/N): Y

Item 2
Enter item price : 20
     Discount(%) : 20
Discounted price : 16.00

Add items (Y/N): n

        *** Purchase Details ***

  Customer Name      : Mickey Mouse
  Number of items is : 2
  Total purchase     : 30.00
  Amount to pay      : 24.00

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

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • Hey, I read through your answer and I found out the problem. So thanks for helping me out. I have also gained a valuable perspective from your answer. Thanks again – Joel Matts Sep 24 '22 at 02:47
  • Glad it helped. Good luck with your coding! If you would like to select this as your answer, please see [What should I do when someone answers my question?](http://stackoverflow.com/help/someone-answers) – David C. Rankin Sep 24 '22 at 02:57
  • Thanks for the tips and how to answer. I am quite new to stack overflow. So Thanks again. – Joel Matts Sep 24 '22 at 02:59
  • You are very welcome. Look forward to watching you develop as a programmer. – David C. Rankin Sep 24 '22 at 03:02