0

I've just started with C programming to prepare for my first class in college. I was practicing writing this simple code when I encountered a problem. I don't know why but the order I put my code alter the final output. Here's my code:

#include "stdio.h"
/* A program to convert customer's coins into dollar slips */

#define DOLL 100              /* Conversion factor for dollar */
#define QURT 25               /* Conversion factor for quarter */
#define DIME 10               /* Conversion factor for dime */
#define NCKL 5                /* Conversion factor for nickel */
int main(void){
    int dollar, quarter, dime,  /* input - count of each coin types */
        nickel, pennies;        /* input - count of each coin types */
    int total;                  /* compute - total of value of coins in cents */
    int leftover;               /* compute - leftover cents */
    int total_dollar;           /* compute - total $ value for credit slip */
    char first, middle, last;   /* input - 3 initials */

    /* Get the count of each kind of coin */
    printf("Number of $ coin> ");
    scanf("%d",&dollar);
    printf("Number of quarter> ");
    scanf("%d",&quarter);
    printf("Number of dimes> ");
    scanf("%d",&dime);
    printf("Number of nickels> ");
    scanf("%d",&nickel);
    printf("Number of pennies> ");
    scanf("%d",&pennies);


    /* Compute for the total value in cents */
    total = dollar * DOLL + quarter * QURT + dime * DIME + nickel * NCKL + pennies;

    /* Compute the final value of credit slip in dollar */
    leftover = total % 100;
    total_dollar = total / 100;

    /* Get the initial for the slip */
    printf("Enter your initial> ");
    scanf("%c%c%c",&first, &middle, &last);

    /* Output */
    printf("Your credit slip>");
    printf("%c%c%c credit",first, middle, last);
    printf("\n%d $ and %d cents",total_dollar, leftover);

    return (0);
}

When I ask for the coins count first and then the initial, I get the wrong result (e.g if I put JRH as initial, it'll only return JR in the end). But if I get the user's initial first, I get the desired result. Can anyone please explain this? Is there a specific order I need to follow that I'm unaware of? Thank you so much!

hn_03
  • 97
  • 1
  • 7
  • C code does not have paragraphs. This is about as clear as mud to me. – Jonathan Wood Jul 09 '15 at 17:11
  • 2
    That's because `scanf` also reads the character value from ENTER key. – jweyrich Jul 09 '15 at 17:12
  • Welcome to undefined behaviour. – Karoly Horvath Jul 09 '15 at 17:14
  • Add your output and both "code orders" else there is not much to say about this. – Norbert Jul 09 '15 at 17:15
  • 1
    You may find [**this question and selected answer**](https://stackoverflow.com/questions/19337351/abnormal-behavior-of-scanf) educational. Parsing the native language barrier, I think you mean it seems to work if you read the character initials *before* the integers, but not if done in the order presented above. if that is your intended meaning, definitely read the linked question. – WhozCraig Jul 09 '15 at 17:15

5 Answers5

2

There's an annoying quirk with using scanf() for individual characters where if you enter something and press "enter", the newline generated by the "enter" keypress can be read in by the next sprintf() call. Most likely, what's happening is that first is getting assigned a newline character, middle is getting "J", and last is getting "R". To verify this, add the following to your output:

printf("0x%02x 0x%02x 0x%02x\n", first, middle, last);

This will show what specific numerical values are in each of these variables. If everything's working correctly, you should see "0x4a 0x52 0x48". I suspect that what you'll actually see is "0x0a 0x4a 0x52".

If this is indeed the case, then see this question for details about what's happening, plus several potential solutions.

bta
  • 43,959
  • 6
  • 69
  • 99
  • 1
    A possible solution for OP would be either a dummy `scanf` call to discard the input buffer, or replacing the `scanf` by `fgets` then parsing the read buffer using `sscanf`. – jweyrich Jul 09 '15 at 17:22
  • @jweyrich: Or flushing stdin after entering pennies. – datenwolf Jul 09 '15 at 17:23
  • @datenwolf: IIRC you can't flush stdin (or any input stream) - that's most likely undefined behavior. – jweyrich Jul 09 '15 at 17:23
  • @jweyrich: The fflush reference says this: `For input streams, fflush() discards any buffered data that has been fetched from the underlying file, but has not been consumed by the application.` – it's perfectly well defined behavior and I'd not see any reason, why this should have been left UB in the first place; there are often situation in which one wants to flush input buffers (e.g. clearing line noise from a modem). – datenwolf Jul 09 '15 at 17:28
  • @datenwolf: That seems innacurate. Where did you get that from? I just queried the C99 standard and it says the following "**If stream points to an output stream** or an update stream in which the **most recent operation was not input**, the fflush function causes any unwritten data for that stream to be delivered to the host environment to be written to the file; **otherwise, the behavior is undefined**." – jweyrich Jul 09 '15 at 17:29
  • @jweyrich: The Linux glibc fflush manpage, which claims it conforms to C89, C99 and POSIX-2001/2008 – datenwolf Jul 09 '15 at 17:32
  • 1
    @jweyrich - It's undefined behavior to the C spec, which means that *anything* can happen. What you describe is a glibc extension. It's standards-compliant behavior because the standard doesn't say what's supposed to happen here. It's not portable, however; many implementations I've encountered simply do nothing when trying to flush an input stream. – bta Jul 09 '15 at 17:34
  • @datenwolf: the behavior may be defined by POSIX or some libc, but it's undefined according to C99 - anything can happen, even what most people expect it to do. So yes, that should work in some systems or with some libc's, but one can't assume it's really portable to any system/libc. – jweyrich Jul 09 '15 at 17:35
  • @bta: Yeah, we're talking the same thing. I just shouldn't have said "seems inaccurate" assuming it was a reference to the language spec (not libc or whatever). – jweyrich Jul 09 '15 at 17:38
  • 1
    The quick and easy solution is to put a leading blank in the format string for the scan: `scanf( " %c%c%c", &first, &middle, &last);`. This will tell `scanf` to skip any leading whitespace left in the input stream from a previous input operation. – John Bode Jul 09 '15 at 17:39
  • @datenwolf: *Some* implementations define the behavior of `fflush` on input streams to clear out the stream, but it's not universally supported (and, IMO, runs counter to the meaning of "flush"). I would not recommend its use. There are other, better ways to deal with garbage in the input stream, although they require some work. – John Bode Jul 09 '15 at 17:39
1

Its because, when you enter pennies and press Enter , It takes '\n' into variable first.

Raman
  • 2,735
  • 1
  • 26
  • 46
1

i think the enter key u press after giving input to number of pennies . This enter key that u press gets stored in your first variable ie "first" when u console when u add the following statement printf("%d %d %d credit",first, middle, last); you will see that the ascii value of the character stored in first is 10 ie nothing but the enter key character as per http://www.astrohandbook.com/files/ascii_codes.html

ASD
  • 107
  • 2
  • 11
1

I'm assuming that by 2nd to last paragraph you are referring you this portion of code:

/* Get the initial for the slip */
printf("Enter your initial> ");
scanf("%c%c%c",&first, &middle, &last);

If that is the case then you are misusing the scanf function, it will see your return from the previous input.

Remember that while an input breaks on return, that return has not been consumed yet, this is also why if you were to place a getchar() directly after that block it would continue. You can fix this by changing your line to the following:

scanf(" %c %c %c",&first, &middle, &last);

Which will parse the input correctly. This is because by placing a space you are going to circumvent the return character and instead go for the next character per your %c input, there are other ways such as clearing the input buffer but this essentially does that without additional need for code.

0

Because %cis very special and should not be used here. All other conversion characters skip over white spaces (blank, tab, new line, cr), but%c reads them.

You should use

scanf("%1s%1s%1s",&first, &middle, &last);

instead to ignore any white spaces.

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252