scanf experiments

Discussion in 'C Programming' started by Steve Zimmerman, Sep 2, 2003.

  1. This post is not intended as an argument to any other post,
    just some simple scanf experiments that I wanted to share.

    I found experiments 5 and 6 the most educational. Also, I
    thought experiment 3 would give some kind of weird error,
    due to the lack of a space between the two `percent d's
    in the scanf statement, but it didn't.


    Experiment 1: ###########################

    int var1, var2;

    printf("Enter two integers: ");
    scanf("%d%d", &var1, &var2);
    /* input from keyboard: 12 13 */

    printf("%d %d\n", var1, var2);
    /* output to screen: 12 13 */

    Experiment 2: ###########################

    int var1, var2;

    printf("Enter two integers: ");
    /* input from keyboard: 12 <enter> 13 */
    scanf("%d %d", &var1, &var2);

    printf("%d %d\n", var1, var2);
    /* output to screen: 12 13 */

    Experiment 3: ###########################

    int var1, var2;

    printf("Enter two integers: ");
    /* input from keyboard: 12 <enter> 13 */
    scanf("%d%d", &var1, &var2);

    printf("%d %d", var1, var2);
    /* output to screen: 12 13 */

    Experiment 4: ############################

    char letter;
    char plus_or_minus;

    printf("Enter your grade: ");
    /* input from keyboard: A+ */
    scanf("%c%c", &letter, &plus_or_minus);

    printf("Your grade is %c%c\n", letter, plus_or_minus);
    /* output to screen: Your grade is A+ */

    Experiment 5: #############################

    char *grade;

    printf("Enter your grade: ");
    /* input from keyboard: A+ */
    scanf("%s", &grade);

    printf("Your grade is %s\n", grade);
    /* output to screen: Segmentation fault */

    Experiment 6: #############################

    char grade[2];

    printf("Enter your grade: ");
    /* input from keyboard: A+ */
    scanf("%s", &grade);

    printf("Your grade is %s\n", grade);
    /* output to screen: Your grade is A+ */

    End of experiments #########################


    Regards,

    --Steve
    Steve Zimmerman, Sep 2, 2003
    #1
    1. Advertising

  2. Steve Zimmerman <> wrote in
    <>:
    >I found experiments 5 and 6 the most educational. Also, I
    >thought experiment 3 would give some kind of weird error,
    >due to the lack of a space between the two `percent d's
    >in the scanf statement, but it didn't.


    <SNIP>
    >Experiment 3: ###########################
    >
    >int var1, var2;
    >
    >printf("Enter two integers: ");
    >/* input from keyboard: 12 <enter> 13 */
    >scanf("%d%d", &var1, &var2);
    >
    >printf("%d %d", var1, var2);
    >/* output to screen: 12 13 */


    Hm, '\n' (produced by hitting enter after '12') is treated as
    a white-space, just like a blank, so what kind of "weird error"
    did you expect?

    <SNIP>
    >Experiment 6: #############################
    >
    >char grade[2];
    >
    >printf("Enter your grade: ");
    >/* input from keyboard: A+ */
    >scanf("%s", &grade);
    >
    >printf("Your grade is %s\n", grade);
    >/* output to screen: Your grade is A+ */


    You're out of luck here: you produced a buffer overflow, but
    nothing serious did happen to show the error!

    Irrwahn,
    member of the scanf()-hater club.
    [No intend to start a flame war.]
    --
    If it's not on fire, it's a software problem.
    Irrwahn Grausewitz, Sep 2, 2003
    #2
    1. Advertising

  3. Steve,

    Steve Zimmerman, 9/1/2003 4:26 PM:
    [...snip...]
    > Experiment 5: #############################
    >
    > char *grade;
    >
    > printf("Enter your grade: ");
    > /* input from keyboard: A+ */
    > scanf("%s", &grade);
    >
    > printf("Your grade is %s\n", grade);
    > /* output to screen: Segmentation fault */


    [...snip...]

    When you experiment with code, turn on all of your compiler
    warnings. The point is to try to make sure you're testing what you
    think you're testing.

    In this particular case, I am not certain what it is you were out to
    find out.

    In particular, if you said something like:

    char grade[100]; /* notice, not char *grade */
    ...
    scanf("%s", grade); /* notice, not &grade */

    then you'd end up with a working piece of code. Of course, as people
    in this newsgroup point out every 5 minutes, there is nothing to
    stop your user from entering >= 100 characters (scanf will add a
    NULL-terminator) and overflow your buffer, producing unpredictable
    results.

    if you said:

    char *grade;
    ...
    scanf("%s", grade); /* notice, not &grade */

    you'd also end up with an unpredictable result, since you'd be
    writing to who-knows-where, since grade points into oblivion.

    However, both of the aforementioned cases would not have produced a
    warning (i think).

    What you're doing in experiment 5, however, produces the following
    warning on my compiler:

    tmp.c:10: warning: char format, pointer arg (arg 2)

    Note, that I am a bit puzzled by the wording. Intuitively, what
    you're doing should produce a warning, and not work as expected :),
    since you are supplying an address of a pointer, instead of
    supplying a pointer to where scanf should write its characters.
    However, I am not certain why gcc says that this is a char format
    and a pointer argument. Regardless of the wording, you'd probably
    get a warning, and go back to see why it is you're getting it :)

    denis


    --
    'From' email address is used as a sink. Not read. Ever.
    Instead, send to [p-o-s-t-i-n-g|o-v-e-r-w-h-e-l-m|n-e-t]
    (remove dashes, replace the first vertical bar with @,
    and second with a dot). Sorry for any inconvenience.
    Denis Perelyubskiy, Sep 2, 2003
    #3
  4. Denis Perelyubskiy wrote:

    > Steve,
    >
    > Steve Zimmerman, 9/1/2003 4:26 PM:
    > [...snip...]
    >
    >> Experiment 5: #############################
    >>
    >> char *grade;
    >>
    >> printf("Enter your grade: ");
    >> /* input from keyboard: A+ */
    >> scanf("%s", &grade);
    >>
    >> printf("Your grade is %s\n", grade);
    >> /* output to screen: Segmentation fault */




    Denis wrote:


    > scanf("%s", grade); /* notice, not &grade */




    Thank you for your advice, Denis; it suggests a new experiment:

    Experiment 8 ###############################################

    char *grade;

    printf("Enter grades of comp.lang.c regulars: ");
    /* input from keyboard: A+ */
    scanf("%s", grade); /* grade with no ampersand */

    printf("Your grade is %s\n", grade);
    /* output to screen: Your grade is A+ */

    #############################################################

    I'm experimenting with scanf to see what behaviors it produces
    with various declarations, various inputs,
    various format strings, and various arguments.

    Your post is quite helpful.


    Regards,

    --Steve
    Steve Zimmerman, Sep 2, 2003
    #4
  5. Steve Zimmerman <> wrote in
    <>:
    >Denis wrote:
    >> scanf("%s", grade); /* notice, not &grade */

    >Thank you for your advice, Denis; it suggests a new experiment:
    >
    >Experiment 8 ###############################################
    >
    >char *grade;
    >
    >printf("Enter grades of comp.lang.c regulars: ");
    >/* input from keyboard: A+ */
    >scanf("%s", grade); /* grade with no ampersand */
    >
    >printf("Your grade is %s\n", grade);
    >/* output to screen: Your grade is A+ */

    Again, you failed to allocate some memory for grade to point to!!!
    And, again, you came out without demons flying out of your nose,
    but still buggy (read: invoking UB) code.

    --
    Air is water with holes in it.
    Irrwahn Grausewitz, Sep 2, 2003
    #5
  6. Steve Zimmerman

    John Bode Guest

    Steve Zimmerman <> wrote in message news:<>...
    > This post is not intended as an argument to any other post,
    > just some simple scanf experiments that I wanted to share.
    >
    > I found experiments 5 and 6 the most educational. Also, I
    > thought experiment 3 would give some kind of weird error,
    > due to the lack of a space between the two `percent d's
    > in the scanf statement, but it didn't.
    >

    [snip]

    > Experiment 3: ###########################
    >
    > int var1, var2;
    >
    > printf("Enter two integers: ");
    > /* input from keyboard: 12 <enter> 13 */
    > scanf("%d%d", &var1, &var2);
    >
    > printf("%d %d", var1, var2);
    > /* output to screen: 12 13 */
    >


    Remember that the %d conversion specifier skips over any leading
    whitespace, so the above behavior isn't "weird" at all. You could
    have hit Enter 100 times between the two inputs; scanf() will discard
    all of them until it sees another string of decimal digits.

    > Experiment 4: ############################
    >
    > char letter;
    > char plus_or_minus;
    >
    > printf("Enter your grade: ");
    > /* input from keyboard: A+ */
    > scanf("%c%c", &letter, &plus_or_minus);
    >
    > printf("Your grade is %c%c\n", letter, plus_or_minus);
    > /* output to screen: Your grade is A+ */
    >


    Gak. Perfectly legal, but from a style perspective...gak. The %c
    specifier is one of the few that doesn't skip leading whitespace, so
    if you fatfinger a space or enter or something, your plus_or_minus
    variable will have garbage in it. Better to read it all as one string
    and then parse out the modifying character separately (I'm a big
    believer in reading whole lines and parsing the line as a separate
    exercise).

    > Experiment 5: #############################
    >
    > char *grade;
    >
    > printf("Enter your grade: ");
    > /* input from keyboard: A+ */
    > scanf("%s", &grade);


    Hint: For the %s conversion specifier, scanf() expects an argument of
    type char *. What is the type of grade? More importantly, what is
    the type of &grade?

    >
    > printf("Your grade is %s\n", grade);
    > /* output to screen: Segmentation fault */


    You understand *why* this happened, right?

    >
    > Experiment 6: #############################
    >
    > char grade[2];
    >
    > printf("Enter your grade: ");
    > /* input from keyboard: A+ */
    > scanf("%s", &grade);
    >


    Same question wrt grade as above. Just because it didn't crash and
    gave the output you expected doesn't mean it's right. There's a bug
    in this line.

    > printf("Your grade is %s\n", grade);
    > /* output to screen: Your grade is A+ */
    >


    Actually, there are two bugs. How big does a char array have to be to
    hold a string N characters long?

    > End of experiments #########################
    >
    >
    > Regards,
    >
    > --Steve
    John Bode, Sep 2, 2003
    #6
  7. (John Bode) wrote in
    <>:
    <SNIP>
    > ... (I'm a big
    >believer in reading whole lines and parsing the line as a separate
    >exercise).

    We should open a scoreboard. It's 3:1 'gainst "TheRealOS/2Guy" already!

    :)

    <SNIP>
    --
    Air is water with holes in it.
    Irrwahn Grausewitz, Sep 2, 2003
    #7
  8. Steve Zimmerman

    John Bode Guest

    Steve Zimmerman <> wrote in message news:<>...
    > Denis Perelyubskiy wrote:
    >
    > > Steve,
    > >
    > > Steve Zimmerman, 9/1/2003 4:26 PM:
    > > [...snip...]
    > >
    > >> Experiment 5: #############################
    > >>
    > >> char *grade;
    > >>
    > >> printf("Enter your grade: ");
    > >> /* input from keyboard: A+ */
    > >> scanf("%s", &grade);
    > >>
    > >> printf("Your grade is %s\n", grade);
    > >> /* output to screen: Segmentation fault */

    >
    >
    >
    > Denis wrote:
    >
    >
    > > scanf("%s", grade); /* notice, not &grade */

    >
    >
    >
    > Thank you for your advice, Denis; it suggests a new experiment:
    >
    > Experiment 8 ###############################################
    >
    > char *grade;
    >
    > printf("Enter grades of comp.lang.c regulars: ");
    > /* input from keyboard: A+ */
    > scanf("%s", grade); /* grade with no ampersand */
    >


    There's still a bug here. Remember that your input string will not be
    stored in the variable grade, but in the chunk of memory that the
    variable grade *points to*. Does grade point anywhere meaningful yet?

    Since grade is declared with auto extent, it isn't explicitly
    initialized to any particular value, and therefore contains some
    random bit string that may or may not correspond to a writable memory
    address. You need to assign the address of a writable chunk of memory
    of the right size to grade *before* you make the call to scanf(),
    either by using malloc() to allocate the memory dynamically, or by
    assigning the address of a statically allocated buffer.

    > printf("Your grade is %s\n", grade);
    > /* output to screen: Your grade is A+ */
    >
    > #############################################################
    >
    > I'm experimenting with scanf to see what behaviors it produces
    > with various declarations, various inputs,
    > various format strings, and various arguments.
    >


    This is the *exact wrong way* to learn *anything* about any
    programming language. You would be much better served by finding an
    authoritative C reference (I use Harbison & Steele's "C: A Reference
    Manual") and reading up on how scanf() is *supposed* to work. It will
    tell you what all the conversion specifiers are, how they recognize
    input, what argument types they expect, etc. It will also tell you
    what will happen if you enter values that cannot be represented by the
    target types.

    Blind experimentation will tell you *nothing* about how C really
    works. You may write a program that appears to work perfectly, but in
    reality invokes undefined behavior that just happens to do the right
    thing for that particular program on that particular machine with that
    particular compiler with that particular combination of options, and
    any change in the above could lead to crashes (if you're lucky) or
    weird behavior (if you're not).

    > Your post is quite helpful.
    >
    >
    > Regards,
    >
    > --Steve
    John Bode, Sep 2, 2003
    #8
  9. Denis Perelyubskiy wrote:

    > In particular, if you said something like:
    >
    > char grade[100]; /* notice, not char *grade */
    > ...
    > scanf("%s", grade); /* notice, not &grade */
    >
    > then you'd end up with a working piece of code. Of course, as people in
    > this newsgroup point out every 5 minutes, there is nothing to stop your
    > user from entering >= 100 characters (scanf will add a NULL-terminator)
    > and overflow your buffer...


    Nothing in the code as written above, but it's trivial to fix it:

    scanf("%99s", grade);

    Allin Cottrell.
    Allin Cottrell, Sep 3, 2003
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Roedy Green

    Experiments with speech to text

    Roedy Green, Jul 4, 2004, in forum: Java
    Replies:
    6
    Views:
    665
    Dale King
    Jul 13, 2004
  2. Steve Zimmerman

    malloc experiments

    Steve Zimmerman, Sep 3, 2003, in forum: C Programming
    Replies:
    52
    Views:
    1,235
    Steve Zimmerman
    Sep 7, 2003
  3. Steve Zimmerman

    malloc experiments

    Steve Zimmerman, Sep 5, 2003, in forum: C Programming
    Replies:
    11
    Views:
    585
    David Gibson
    Sep 10, 2003
  4. =?ISO-8859-1?Q?Martin_J=F8rgensen?=

    scanf (yes/no) - doesn't work + deprecation errors scanf, fopen etc.

    =?ISO-8859-1?Q?Martin_J=F8rgensen?=, Feb 16, 2006, in forum: C Programming
    Replies:
    185
    Views:
    3,386
    those who know me have no need of my name
    Apr 3, 2006
  5. =?ISO-8859-1?Q?Martin_J=F8rgensen?=

    difference between scanf("%i") and scanf("%d") ??? perhaps bug inVS2005?

    =?ISO-8859-1?Q?Martin_J=F8rgensen?=, Apr 26, 2006, in forum: C Programming
    Replies:
    18
    Views:
    673
    Richard Bos
    May 2, 2006
Loading...

Share This Page