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.