Proper use of scanf

Discussion in 'C Programming' started by Lefty Bigfoot, Jun 18, 2005.

  1. Hello,

    I am aware that a lot of people are wary of using scanf,
    because doing it improperly can be dangerous. I have
    tried to find a good tutorial on all the ins and outs
    of scanf() but been unsuccessful.

    Is there a well-respected (by the c.l.c crowd) book
    or tutorial that really covers scanf in detail?
    Lefty Bigfoot, Jun 18, 2005
    #1
    1. Advertising

  2. Lefty Bigfoot

    pete Guest

    Lefty Bigfoot wrote:
    >
    > Hello,
    >
    > I am aware that a lot of people are wary of using scanf,
    > because doing it improperly can be dangerous. I have
    > tried to find a good tutorial on all the ins and outs
    > of scanf() but been unsuccessful.
    >
    > Is there a well-respected (by the c.l.c crowd) book
    > or tutorial that really covers scanf in detail?


    I don't know of one.
    Here's two examples of one way to use scanf safely.
    If you enter more than LENGTH characters,
    the extra ones will be automatically discarded.
    If you have questions, I can try to explain.
    The whole topic of scanf is somewhat lengthy.

    /* BEGIN anystring.c */

    #include <stdio.h>

    #define LENGTH 20
    #define str(x) #x
    #define xstr(x) str(x)

    int main(void)
    {
    char string[LENGTH + 1];
    int rc;

    printf("Enter any string or enter an empty string to quit: ");
    fflush(stdout);
    rc = scanf("%" xstr(LENGTH) "[^\n]%*[^\n]", string);
    if (!feof(stdin)) {
    getchar();
    }
    while (rc == 1) {
    printf("Your string was %s\n", string);
    printf("scanf() returned %d\n", rc);
    printf("Enter any string or enter an empty string to quit: ");
    fflush(stdout);
    rc = scanf("%" xstr(LENGTH) "[^\n]%*[^\n]", string);
    if (!feof(stdin)) {
    getchar();
    }
    }
    printf("scanf() returned %d\n", rc);
    return 0;
    }

    /* END anystring.c */


    /* BEGIN grade.c */

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

    #define LENGTH 3
    #define str(x) # x
    #define xstr(x) str(x)

    int main(void)
    {
    int rc;
    char array[LENGTH + 1];
    long number;
    const char letter[4] = "DCBA";

    fputs("Enter the Numeric grade: ", stdout);
    fflush(stdout);
    rc = scanf("%" xstr(LENGTH) "[^\n]%*[^\n]", array);
    if (!feof(stdin)) {
    getchar();
    }
    while (rc == 1) {
    number = strtol(array, NULL, 10);
    if (number > 60) {
    if (number > 99) {
    number = 99;
    }
    array[0] = letter[(number - 60) / 10];
    switch (number % 10) {
    case 0:
    case 1:
    array[1] = '-';
    array[2] = '\0';
    break;
    case 8:
    case 9:
    array[1] = '+';
    array[2] = '\0';
    break;
    default:
    array[1] = '\0';
    break;
    }
    } else {
    array[0] = 'F';
    array[1] = '\0';
    }
    printf("The Letter grade is: %s\n", array);
    fputs("Enter the Numeric grade: ", stdout);
    fflush(stdout);
    rc = scanf("%" xstr(LENGTH) "[^\n]%*[^\n]", array);
    if (!feof(stdin)) {
    getchar();
    }
    }
    return 0;
    }

    /* END grade.c */


    --
    pete
    pete, Jun 19, 2005
    #2
    1. Advertising

  3. Le 19/06/2005 00:54, dans ,
    « Lefty Bigfoot » <> a écrit :

    >
    > Hello,
    >
    > I am aware that a lot of people are wary of using scanf,
    > because doing it improperly can be dangerous. I have
    > tried to find a good tutorial on all the ins and outs
    > of scanf() but been unsuccessful.
    >
    > Is there a well-respected (by the c.l.c crowd) book
    > or tutorial that really covers scanf in detail?


    Yes, the ISO 9899-1999 Standard, section 7.19.6.4.
    I can swear it's well respected here :)

    There is also the POSIX standard, at
    http://www.opengroup.org/onlinepubs/000095399/
    certainly well respected too.

    If you want a tutorial, maybe the K&R C book will help you.

    If you have UNIX or Linux, try "man scanf"
    Jean-Claude Arbaut, Jun 19, 2005
    #3
  4. Lefty Bigfoot

    CBFalconer Guest

    Lefty Bigfoot wrote:
    >
    > I am aware that a lot of people are wary of using scanf,
    > because doing it improperly can be dangerous. I have
    > tried to find a good tutorial on all the ins and outs
    > of scanf() but been unsuccessful.
    >
    > Is there a well-respected (by the c.l.c crowd) book
    > or tutorial that really covers scanf in detail?


    Take a look at the links in my sig. Especially the one marked
    C-library, and then the C99 one.

    --
    Some useful references about C:
    <http://www.ungerhu.com/jxh/clc.welcome.txt>
    <http://www.eskimo.com/~scs/C-faq/top.html>
    <http://benpfaff.org/writings/clc/off-topic.html>
    <http://anubis.dkuug.dk/jtc1/sc22/wg14/www/docs/n869/> (C99)
    <http://www.dinkumware.com/refxc.html> (C-library}
    <http://gcc.gnu.org/onlinedocs/> (GNU docs)
    CBFalconer, Jun 19, 2005
    #4
  5. Lefty Bigfoot

    Vivek Guest

    There seems to be some problem with the way I am using scanf() in my
    code. Could please help me out?

    /*Sample Program*/

    #include<stdio.h>

    int main()
    {
    double D;

    scanf("%g", &D);
    printf("%g", D);

    return 0;
    }

    /*During Execution*/
    1232 /*Input*/

    5.68642e-315/*Output*/

    /*End*/

    If it helps, I am using the gcc compiler(ver 3.4.3) that I got with
    DJGPP and I am using it on Win98.
    Vivek, Jun 19, 2005
    #5
  6. Lefty Bigfoot

    Vivek Guest

    Hello,

    I just found a post from a person having the same problem. How cool is
    that! The one mistake I found out is that '%g' in the scanf should be
    '%lg'. Anyother nit picking will be welcomed.
    Vivek, Jun 19, 2005
    #6
  7. Vivek wrote:
    > There seems to be some problem with the way I am using scanf() in my
    > code. Could please help me out?
    >
    > /*Sample Program*/
    > #include<stdio.h>
    > int main()
    > {
    > double D;
    > scanf("%g", &D);
    > printf("%g", D);
    > return 0;
    > }
    >
    > /*During Execution*/
    > 1232 /*Input*/
    > 5.68642e-315/*Output*/



    #include<stdio.h>

    int main(void)
    {
    double D;
    char input[] = "1234";

    printf("Using the OP's incorrect specifier for\n"
    "reading the string \"%s\" as a double:", input);
    sscanf(input, "%g", &D);
    printf("%g\n", D);

    printf("Using the correct specifier for\n"
    "reading the string \"%s\" as a double:", input);
    sscanf(input, "%lg", &D);
    printf("%g\n", D);

    return 0;
    }

    [output]
    Using the OP's incorrect specifier for
    reading the string "1234" as a double:2.88675e-13
    Using the correct specifier for
    reading the string "1234" as a double:1234

    > If it helps, I am using the gcc compiler(ver 3.4.3) that I got with
    > DJGPP and I am using it on Win98.


    If you had turned on the warnings during compilation, gcc would have
    told you the specifier was wrong. Not all compilers are so obliging.
    Keep those warning levels up, and don't ignore the diagnostics.
    Martin Ambuhl, Jun 19, 2005
    #7
  8. Lefty Bigfoot

    Eric Sosman Guest

    Vivek wrote:
    > There seems to be some problem with the way I am using scanf() in my
    > code. Could please help me out?
    > [...]
    > double D;
    > scanf("%g", &D);
    > [...]
    >
    > If it helps, I am using the gcc compiler(ver 3.4.3) that I got with
    > DJGPP and I am using it on Win98.


    The compiler you're using happens to be able to
    catch this error for you, if you ask it nicely. Use
    the command-line flags "-Wall -W"; for code that's
    intended to be portable use "-Wall -W -ansi -pedantic".
    (There are alternatives to "-ansi"; see the info pages.)

    --
    Eric Sosman
    lid
    Eric Sosman, Jun 19, 2005
    #8
  9. Lefty Bigfoot

    CBFalconer Guest

    Eric Sosman wrote:
    > Vivek wrote:
    >
    >> There seems to be some problem with the way I am using scanf()
    >> in my code. Could please help me out?
    >> [...]
    >> double D;
    >> scanf("%g", &D);
    >> [...]
    >>
    >> If it helps, I am using the gcc compiler(ver 3.4.3) that I got
    >> with DJGPP and I am using it on Win98.

    >
    > The compiler you're using happens to be able to
    > catch this error for you, if you ask it nicely. Use
    > the command-line flags "-Wall -W"; for code that's
    > intended to be portable use "-Wall -W -ansi -pedantic".
    > (There are alternatives to "-ansi"; see the info pages.)


    This is one more of a long list of anomalies in scanf, and adds to
    the list of reasons not to use it. Unfortunately the C library
    lacks good routines to input from streams (rather than buffers). I
    have written and published some suitable routines in the past.

    To the OP - look up the modifier l (small ell) in the scanf
    documentation. Read it with great care. Then don't use it, get
    complete lines and work on those.

    --
    Some informative links:
    news:news.announce.newusers
    http://www.geocities.com/nnqweb/
    http://www.catb.org/~esr/faqs/smart-questions.html
    http://www.caliburn.nl/topposting.html
    http://www.netmeister.org/news/learn2quote.html
    CBFalconer, Jun 19, 2005
    #9
  10. Lefty Bigfoot

    Jack Klein Guest

    On Sun, 19 Jun 2005 02:08:52 +0200, Jean-Claude Arbaut
    <> wrote in comp.lang.c:

    >
    > Le 19/06/2005 00:54, dans ,
    > « Lefty Bigfoot » <> a écrit :
    >
    > >
    > > Hello,
    > >
    > > I am aware that a lot of people are wary of using scanf,
    > > because doing it improperly can be dangerous. I have
    > > tried to find a good tutorial on all the ins and outs
    > > of scanf() but been unsuccessful.
    > >
    > > Is there a well-respected (by the c.l.c crowd) book
    > > or tutorial that really covers scanf in detail?

    >
    > Yes, the ISO 9899-1999 Standard, section 7.19.6.4.
    > I can swear it's well respected here :)


    That's actually not a reference to how to use the function safely, nor
    even a recommendation that it should be used.

    See 7.19.7.7, which describes the gets() function, and includes not so
    much as a hint of a warning about buffer overflows.

    > There is also the POSIX standard, at
    > http://www.opengroup.org/onlinepubs/000095399/
    > certainly well respected too.
    >
    > If you want a tutorial, maybe the K&R C book will help you.
    >
    > If you have UNIX or Linux, try "man scanf"


    The general consensus here, which I agree with, is that the *scanf()
    functions are best avoided by all except extreme experts on their use.
    If non-experts avoid them, the will never become extreme experts,
    making the point moot.

    --
    Jack Klein
    Home: http://JK-Technology.Com
    FAQs for
    comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
    comp.lang.c++ http://www.parashift.com/c -faq-lite/
    alt.comp.lang.learn.c-c++
    http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html
    Jack Klein, Jun 20, 2005
    #10
  11. On 20/06/2005 05:19, Jack Klein wrote:

    > On Sun, 19 Jun 2005 02:08:52 +0200, Jean-Claude Arbaut
    > <> wrote in comp.lang.c:
    >
    >>

    > That's actually not a reference to how to use the function safely, nor
    > even a recommendation that it should be used.
    >
    > See 7.19.7.7, which describes the gets() function, and includes not so
    > much as a hint of a warning about buffer overflows.


    Oopss :)


    > The general consensus here, which I agree with, is that the *scanf()
    > functions are best avoided by all except extreme experts on their use.
    > If non-experts avoid them, the will never become extreme experts,
    > making the point moot.


    Anyway it's certainly good practice not to use a function when one has
    doubts on its use. Concerning scanf, it's rarely useful, because of its
    strange behaviour, at least on some implementations (if I remember well, you
    may enter an infinite loop if you enter wrong data when an integer is
    expected, not merely because of scanf, because of the program that uses it).
    I mainly use it in toy programs.
    Jean-Claude Arbaut, Jun 20, 2005
    #11
  12. Lefty Bigfoot

    Eric Sosman Guest

    Jack Klein wrote:
    > [...]
    > The general consensus here, which I agree with, is that the *scanf()
    > functions are best avoided by all except extreme experts on their use.
    > If non-experts avoid them, the will never become extreme experts,
    > making the point moot.


    I'd agree that scanf() and fscanf() are best avoided,
    but sscanf() is both usable and useful. fgets()/sscanf()
    make a good combination.

    --
    Eric Sosman
    lid
    Eric Sosman, Jun 20, 2005
    #12
  13. Lefty Bigfoot

    Guest

    Lefty Bigfoot wrote:
    > Hello,
    >
    > I am aware that a lot of people are wary of using scanf,
    > because doing it improperly can be dangerous. I have
    > tried to find a good tutorial on all the ins and outs
    > of scanf() but been unsuccessful.
    >
    > Is there a well-respected (by the c.l.c crowd) book
    > or tutorial that really covers scanf in detail?


    There is also a useful reference in the documentation of the GNU
    standard C library

    http://www.gnu.org/software/libc/manual/html_mono/libc.html.gz#Formatted Output Functions

    This also mentions many GNU extensions though.
    , Jun 20, 2005
    #13
  14. Lefty Bigfoot

    Ben Pfaff Guest

    Eric Sosman <> writes:

    > I'd agree that scanf() and fscanf() are best avoided,
    > but sscanf() is both usable and useful.


    Only if one doesn't mind the nasal demons that are emitted when a
    conversion's value cannot be represented in the object it is
    stored into, e.g. when an out-of-range number is read.
    --
    "The expression isn't unclear *at all* and only an expert could actually
    have doubts about it"
    --Dan Pop
    Ben Pfaff, Jun 20, 2005
    #14
  15. Lefty Bigfoot

    Eric Sosman Guest

    Ben Pfaff wrote:
    > Eric Sosman <> writes:
    >
    >
    >> I'd agree that scanf() and fscanf() are best avoided,
    >>but sscanf() is both usable and useful.

    >
    >
    > Only if one doesn't mind the nasal demons that are emitted when a
    > conversion's value cannot be represented in the object it is
    > stored into, e.g. when an out-of-range number is read.


    Hmmm ... I'd always assumed that'd be a "matching
    failure," but no: trying to derive an eight-bit `char'
    value from "666" is, indeed, U.B. You learn something
    new every day.

    --
    Eric Sosman, Jun 20, 2005
    #15
  16. Lefty Bigfoot

    Jack Klein Guest

    On Mon, 20 Jun 2005 07:39:46 -0400, Eric Sosman
    <> wrote in comp.lang.c:

    > Jack Klein wrote:
    > > [...]
    > > The general consensus here, which I agree with, is that the *scanf()
    > > functions are best avoided by all except extreme experts on their use.
    > > If non-experts avoid them, the will never become extreme experts,
    > > making the point moot.

    >
    > I'd agree that scanf() and fscanf() are best avoided,
    > but sscanf() is both usable and useful. fgets()/sscanf()
    > make a good combination.


    As Ben already pointed out, all the members of *scanf() produce
    undefined behavior if the result of a numeric conversion is out of
    range for the destination type.

    Which means to use them safely, you need to pre-check the numeric
    digits before converting. If you are going to check them by hand, you
    might as well do the conversion yourself, it takes little additional
    effort.

    Now fgets() and { strol(), strtod(), strtoul(), strtoll(), stroull() }
    make a robust combination.

    --
    Jack Klein
    Home: http://JK-Technology.Com
    FAQs for
    comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
    comp.lang.c++ http://www.parashift.com/c -faq-lite/
    alt.comp.lang.learn.c-c++
    http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html
    Jack Klein, Jun 21, 2005
    #16
  17. Lefty Bigfoot

    CBFalconer Guest

    Jack Klein wrote:
    > On Mon, 20 Jun 2005 07:39:46 -0400, Eric Sosman
    > > Jack Klein wrote:

    >
    >>> [...]
    >>> The general consensus here, which I agree with, is that the
    >>> *scanf() functions are best avoided by all except extreme
    >>> experts on their use. If non-experts avoid them, the will
    >>> never become extreme experts, making the point moot.

    >>
    >> I'd agree that scanf() and fscanf() are best avoided,
    >> but sscanf() is both usable and useful. fgets()/sscanf()
    >> make a good combination.

    >
    > As Ben already pointed out, all the members of *scanf() produce
    > undefined behavior if the result of a numeric conversion is out
    > of range for the destination type.
    >
    > Which means to use them safely, you need to pre-check the numeric
    > digits before converting. If you are going to check them by hand,
    > you might as well do the conversion yourself, it takes little
    > additional effort.
    >
    > Now fgets() and { strol(), strtod(), strtoul(), strtoll(),
    > stroull() } make a robust combination.


    The only problem with that is that you have to assign a buffer. I
    have published some routines which operate directly on the input
    stream, and need no buffers (as does scanf). However my routines
    are not variadic, and do not involve loading a large interpreter
    system. They also have comprehensive error reporting, and do such
    things as absorbing a complete numeric field even when the value
    overflows. These are worthwhile considerations, especially in a
    resource starved embedded system.

    The following is a sample of the routines:

    /*--------------------------------------------------------------
    * Read an unsigned value. Signal error for overflow or no
    * valid number found. Returns true for error, false for noerror
    *
    * Skip all leading whitespace on f. At completion getc(f) will
    * return the character terminating the number, which may be \n
    * or EOF among others. Barring EOF it will NOT be a digit. The
    * combination of error, zero, and the following getc returning
    * \n indicates that no numerical value was found on the line.
    *
    * If the user wants to skip all leading white space including
    * \n, \f, \v, \r, he should first call "skipwhite(f);"
    *
    * Peculiarity: This specifically forbids a leading '+' or '-'.
    * Peculiarity: This forbids overflow, unlike C unsigned usage.
    * on overflow, UINT_MAX is returned.
    */
    int readxwd(unsigned int *wd, FILE *f)
    {
    unsigned int value, digit;
    int status;
    int ch;

    #define UWARNLVL (UINT_MAX / 10U)
    #define UWARNDIG (UINT_MAX - UWARNLVL * 10U)

    value = 0; /* default */
    status = 1; /* default error */

    do {
    ch = getc(f);
    } while ((' ' == ch) || ('\t' == ch)); /* skipblanks */
    /* while (isblank((UCHAR)ch)); */ /* for C99 */

    if (!(EOF == ch)) {
    if (isdigit((UCHAR)ch)) /* digit, no error */
    status = 0;
    while (isdigit((UCHAR)ch)) {
    digit = (unsigned) (ch - '0');
    if ((value < UWARNLVL) ||
    ((UWARNLVL == value) && (UWARNDIG >= digit)))
    value = 10 * value + digit;
    else { /* overflow */
    status = 1;
    value = UINT_MAX;
    }
    ch = getc(f);
    } /* while (ch is a digit) */
    }
    *wd = value;
    ungetc(ch, f);
    return status;
    } /* readxwd */

    --
    Some informative links:
    news:news.announce.newusers
    http://www.geocities.com/nnqweb/
    http://www.catb.org/~esr/faqs/smart-questions.html
    http://www.caliburn.nl/topposting.html
    http://www.netmeister.org/news/learn2quote.html
    CBFalconer, Jun 21, 2005
    #17
  18. CBFalconer wrote:
    > ...
    > int ch;
    > ch = getc(f);
    > ...
    > if (!(EOF == ch)) {
    > if (isdigit((UCHAR)ch)) /* digit, no error */


    Since getc already returns a value in the range of unsigned
    char, there's nothing to gain by adding the UCHAR (presumably
    unsigned char) cast.

    If you're worried that UCHAR_MAX > INT_MAX, then you should
    be performing a specific feof check.

    > status = 0;
    > while (isdigit((UCHAR)ch)) {
    > digit = (unsigned) (ch - '0');
    > if ((value < UWARNLVL) ||
    > ((UWARNLVL == value) && (UWARNDIG >= digit)))
    > value = 10 * value + digit;
    > else { /* overflow */
    > status = 1;
    > value = UINT_MAX;
    > }
    > ch = getc(f);
    > } /* while (ch is a digit) */


    For unsigned int, you can simplify the overflow check to...

    while (isdigit(ch))
    {
    new_value = 10 * value + ch - '0';
    if (new_value < value) { status = 1; new_value = -1; }
    value = new_value;
    ch = getc(f);
    }

    --
    Peter
    Peter Nilsson, Jun 21, 2005
    #18
    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. sushant
    Replies:
    4
    Views:
    8,949
    Chris Torek
    Jan 10, 2005
  2. =?utf-8?B?55ee5a2Q?=

    how to use scanf()?

    =?utf-8?B?55ee5a2Q?=, May 24, 2005, in forum: C Programming
    Replies:
    1
    Views:
    590
    Keith Thompson
    May 24, 2005
  3. =?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,334
    those who know me have no need of my name
    Apr 3, 2006
  4. =?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:
    655
    Richard Bos
    May 2, 2006
  5. H. Wade Minter
    Replies:
    8
    Views:
    267
    Robin
    Apr 25, 2004
Loading...

Share This Page