Only number input thru scanf()

Discussion in 'C Programming' started by Sandy Beech, Nov 2, 2010.

  1. Sandy Beech

    Sandy Beech Guest

    Hello,

    I want to restrict the input from the user only to numbers. How can i
    do that with scanf()? Is there any other way i can do that ? Also i want
    the scanf() to accept even the carriage return without entering
    anything. How can i acheive that? Please help me out.
    Sandy Beech, Nov 2, 2010
    #1
    1. Advertising

  2. On Nov 2, 2:42 pm, Sandy Beech <> wrote:
    > Hello,
    >
    >  I want to restrict the input from the user only to numbers. How can i
    > do that with scanf()? Is there any other way i can do that ? Also i want
    > the scanf() to accept even the carriage return without entering
    > anything. How can i acheive that? Please help me out.


    You need to create a specialized entry function or do something OS
    specific in order to restrict input. In most cases, these specialized
    entry functions simply ignore and refuse to echo input characters that
    are not appropriate for the type of data input (and maybe even beep,
    flash, or shout, if the user types something else).

    In any case, scanf() is not your friend on this. I'm not saying that
    you can't do what you want with some repeated and creative application
    of scanf(), but scanf() certianly isn't written for this purpose.
    Michael Angelo Ravera, Nov 2, 2010
    #2
    1. Advertising

  3. Sandy Beech

    Felix Palmen Guest

    * Sandy Beech <>:
    > I want to restrict the input from the user only to numbers. How can i
    > do that with scanf()? Is there any other way i can do that ? Also i want
    > the scanf() to accept even the carriage return without entering
    > anything. How can i acheive that? Please help me out.


    You can't. Either check user input later, optionally telling the user
    what went wrong and letting him repeat the input, or sacrifice
    portability and do it yourself, using things like conio on windows or
    raw terminal mode on *nix.

    Regards,
    Felix

    --
    Felix Palmen (Zirias) + [PGP] Felix Palmen <>
    web: http://palmen-it.de/ | http://palmen-it.de/pub.txt
    my open source projects: | Fingerprint: ED9B 62D0 BE39 32F9 2488
    http://palmen-it.de/?pg=pro + 5D0C 8177 9D80 5ECF F683
    Felix Palmen, Nov 2, 2010
    #3
  4. Sandy Beech <> wrote:
    >  I want to restrict the input from the user only to numbers.
    > How can i do that with scanf()?


    Effectively, you can't.

    > Is there any other way i can do that ? Also i want
    > the scanf() to accept even the carriage return without
    > entering anything.


    Use fgets, then sscanf, or better still strtol.

    --
    Peter
    Peter Nilsson, Nov 3, 2010
    #4
  5. Sandy Beech <> writes:
    > I want to restrict the input from the user only to numbers. How can i
    > do that with scanf()? Is there any other way i can do that ? Also i want
    > the scanf() to accept even the carriage return without entering
    > anything. How can i acheive that? Please help me out.


    What exactly do you mean by "restrict"? If the user types something
    other than a number, what should happen?

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Nov 3, 2010
    #5
  6. Groovy hepcat Felix Palmen was jivin' in comp.lang.c on Wed, 3 Nov 2010
    9:17 am. It's a cool scene! Dig it.

    > * Sandy Beech <>:
    >> I want to restrict the input from the user only to numbers. How can i
    >> do that with scanf()? Is there any other way i can do that ? Also i
    >> want the scanf() to accept even the carriage return without entering
    >> anything. How can i acheive that? Please help me out.

    >
    > You can't.


    Nonsense! You certainly can do that. Of course, scanf() may not be the
    best function for the job. The OP should read the FAQ for more on this.
    I'd maybe use fgets() followed by sscanf(). This would also provide a
    trivial way to determine whether the input contains only a newline.
    But to give you some idea what can be done using only scanf() for
    input, consider the following code:

    #include <stdio.h>

    int main(void)
    {
    int nfields, num;
    char dummy[2];

    fputs("Please enter a decimal integer: ", stdout);
    fflush(stdout);

    nfields = scanf("%d%1[^\n]", &num, dummy);
    while(1 != nfields)
    {
    puts("Invalid input! Please try again.");
    fputs("Enter a decimal integer (and nothing else): ", stdout);
    fflush(stdout);

    /* Consume remaining line of input. */
    while(0 != scanf("%*[^\n]"))
    ;

    nfields = scanf("%d%1[^\n]", &num, dummy);
    }

    printf("num = %d\n", num);
    }

    This code first prompts for a number, then attempts to read in two
    fields: a decimal integer and a single character that is not a newline
    (as indicated by the %1[^\n] conversion specifier). However, we want it
    to fail to read the second field. There are several scenarios that can
    be encountered:

    1) no fields are read in, meaning there are no digits at the start of
    the input, scanf() returns 0, and we enter the loop to try again (after
    consuming the remaining line of input so we don't get stuck in an
    endless loop);

    2) a numerical field and an extra character field are read in, meaning
    there are digits at the start of the input but there is some non-digit
    character(s) after that, scanf() returns 2, and the loop is entered to
    try again;

    3) a numerical field is read, but no other characters are present, and
    scanf() returns 1, meaning that only digits were entered, which is what
    we want, so we don't enter the loop.

    The last printf() statement then tells us what number was entered, and
    the program ends.
    To determine whether a newline has been entered is also trivial using
    scanf(). The %c conversion specifier reads the next character, even if
    it is white space. Regardez:

    char ch;
    scanf("%c", &ch);
    if('\n' == ch)
    {
    /* Newline has been entered. */
    }

    Or you could use the %1[\n] conversion specifier to force scanf() to
    read only a single newline. Note that this treats the input as a
    string, even if it is only one character long (which it will be since
    any character other than a single newline will be rejected), so you
    need an array of at least two bytes (for the input and null).

    char s[2];
    if(1 == scanf("%1[\n]", s))
    {
    /* Newline has been entered. */
    }

    --
    Dig the sig!

    ----------- Peter 'Shaggy' Haywood ------------
    Ain't I'm a dawg!!
    Peter 'Shaggy' Haywood, Nov 3, 2010
    #6
  7. Sandy Beech

    David RF Guest

    On 2 nov, 22:42, Sandy Beech <> wrote:
    > Hello,
    >
    >  I want to restrict the input from the user only to numbers. How can i
    > do that with scanf()? Is there any other way i can do that ? Also i want
    > the scanf() to accept even the carriage return without entering
    > anything. How can i acheive that? Please help me out.


    If you are under a unix shell you can use termios

    A little example (never tested in real production, any advice is
    welcomed)

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <ctype.h>
    #include <termios.h>
    #include <unistd.h>

    #define KEY_TAB 0x0009 /* 9 */
    #define KEY_ENTER 0x000a /* 10 */
    #define KEY_ESCAPE 0x001b /* 27 */
    #define KEY_BACKSPACE 0x007f /* 127 */

    #define KEY_DELETE 0x0100 /* 256 */
    #define KEY_HOME 0x0101
    #define KEY_END 0x0102
    #define KEY_REPAG 0x0103
    #define KEY_AVPAG 0x0104
    #define KEY_UP 0x0105
    #define KEY_DOWN 0x0106
    #define KEY_LEFT 0x0107
    #define KEY_RIGHT 0x0108

    /* Macros terminal */
    #define cursorforward(x) printf("\033[%dC", (x))
    #define cursorbackward(x) printf("\033[%dD", (x))
    #define savecursor() printf("\033[s")
    #define unsavecursor() printf("\033[u")
    /* END Macros terminal */

    static struct termios term, oterm;

    static int getch(void);
    static int kbhit(void);
    static int kbesc(void);
    static int kbget(void);

    static int getch(void)
    {
    int c = 0;

    tcgetattr(0, &oterm);
    memcpy(&term, &oterm, sizeof(term));
    term.c_lflag &= ~(ICANON | ECHO);
    term.c_cc[VMIN] = 1;
    term.c_cc[VTIME] = 0;
    tcsetattr(0, TCSANOW, &term);
    c = getchar();
    tcsetattr(0, TCSANOW, &oterm);
    return c;
    }

    static int kbhit(void)
    {
    int c = 0;

    tcgetattr(0, &oterm);
    memcpy(&term, &oterm, sizeof(term));
    term.c_lflag &= ~(ICANON | ECHO);
    term.c_cc[VMIN] = 0;
    term.c_cc[VTIME] = 1;
    tcsetattr(0, TCSANOW, &term);
    c = getchar();
    tcsetattr(0, TCSANOW, &oterm);
    if (c != -1) ungetc(c, stdin);
    return ((c != -1) ? 1 : 0);
    }

    static int kbesc(void)
    {
    int c;

    if (!kbhit()) return KEY_ESCAPE;
    c = getch();
    if ((c == '[') || (c == 'O')) {
    switch (getch()) {
    case 'A':
    c = KEY_UP;
    break;
    case 'B':
    c = KEY_DOWN;
    break;
    case 'C':
    c = KEY_LEFT;
    break;
    case 'D':
    c = KEY_RIGHT;
    break;
    case 'F':
    c = KEY_END;
    break;
    case 'H':
    c = KEY_HOME;
    break;
    case '1':
    if (getch() == '~') c = KEY_HOME; else c = 0;
    break;
    case '3':
    if (getch() == '~') c = KEY_DELETE; else c = 0;
    break;
    case '4':
    if (getch() == '~') c = KEY_END; else c = 0;
    break;
    case '5':
    if (getch() == '~') c = KEY_REPAG; else c = 0;
    break;
    case '6':
    if (getch() == '~') c = KEY_AVPAG; else c = 0;
    break;
    default:
    c = 0;
    break;
    }
    } else {
    c = 0;
    }
    if (c == 0) while (kbhit()) getch();
    return c;
    }

    static int kbget(void)
    {
    int c;

    c = getch();
    return (c == KEY_ESCAPE) ? kbesc() : c;
    }

    char *inputfn(size_t size, int (*fn)(int))
    {
    int c, pos = 0, len = 0;
    char *entry;

    entry = calloc(size + 1, sizeof(char));
    if (entry == NULL) {
    fprintf(stderr, "Aargh ...");
    exit(EXIT_FAILURE);
    }
    for (;;) {
    c = kbget();
    if (
    c == KEY_ENTER || c == KEY_ESCAPE ||
    c == KEY_TAB || c == KEY_REPAG || c == KEY_AVPAG ||
    c == KEY_UP || c == KEY_DOWN
    ) break;
    if (c == KEY_BACKSPACE) {
    if (pos > 0) {
    pos--;
    putchar('\b');
    c = KEY_DELETE;
    } else continue;
    }
    if (c == KEY_DELETE) {
    if (pos < len) {
    memmove(&entry[pos], &entry[pos + 1], (size_t)(len - pos));
    len--;
    savecursor();
    printf("%s ", &entry[pos]);
    unsavecursor();
    }
    } else
    if (c == KEY_HOME) {
    if (pos > 0) {
    cursorbackward(pos);
    pos = 0;
    }
    } else
    if (c == KEY_END) {
    if (pos < len) {
    cursorforward(len - pos);
    pos = len;
    }
    } else
    if (c == KEY_RIGHT) {
    if (pos > 0) {
    pos--;
    putchar('\b');
    }
    } else
    if (c == KEY_LEFT) {
    if (pos < len) {
    putchar(entry[pos++]);
    }
    } else
    if (fn && fn((unsigned char)c)) {
    /* Si es el primer caracter de la cadena borra todo */
    /* if first char delete all */
    if (pos == 0 && len > 1) {
    memset(entry, 0, (size_t)len);
    savecursor();
    printf("%*s", len, "");
    unsavecursor();
    len = 0;
    }
    if (pos == len) {
    if (len == size) continue;
    len++;
    }
    entry[pos++] = (char)c;
    putchar(c);
    }
    }
    return entry;
    }

    int main(void)
    {
    char *entry;

    printf("Input number: ");
    entry = inputfn(5, isdigit);
    /* where 5 is max input and isdigit a filter (you can use any ctype
    or you own) */
    printf("\nYour number is %s\n", entry);
    free(entry);

    return 0;
    }
    David RF, Nov 3, 2010
    #7
  8. Peter 'Shaggy' Haywood <> writes:
    > Groovy hepcat Felix Palmen was jivin' in comp.lang.c on Wed, 3 Nov 2010
    > 9:17 am. It's a cool scene! Dig it.
    >
    >> * Sandy Beech <>:
    >>> I want to restrict the input from the user only to numbers. How can i
    >>> do that with scanf()? Is there any other way i can do that ? Also i
    >>> want the scanf() to accept even the carriage return without entering
    >>> anything. How can i acheive that? Please help me out.

    >>
    >> You can't.

    >
    > Nonsense! You certainly can do that. Of course, scanf() may not be the
    > best function for the job. The OP should read the FAQ for more on this.

    [snip]

    It depends on just what the OP is trying to accomplish. In particular,
    it depends on what the OP means by "restrict". (I asked, and I haven't
    seen a response.)

    Here's an example of something the OP *might* have meant, something
    that can't be done in portable and/or standard C. I once wrote a
    numeric input routine that would accept only well-formed numeric
    input. If the user typed a character that could not be part of
    a number, it was discarded, not even echoed. For example, if the
    user typed "12xyz34", only "1234" would appear on the screen, and
    the input value would be 1234.

    If you're not going to play that kind of trick to disallow invalid
    input, you have to decide how to respond when the user enters something
    other than a number. I suspect the OP hasn't thought about that.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Nov 6, 2010
    #8
  9. On Wed, 03 Nov 2010 19:27:29 +1100, Peter 'Shaggy' Haywood
    <> wrote:

    > But to give you some idea what can be done using only scanf() for
    > input, consider the following code:


    > nfields = scanf("%d%1[^\n]", &num, dummy);
    > while(1 != nfields)
    > {
    > puts("Invalid input! Please try again.");
    > fputs("Enter a decimal integer (and nothing else): ", stdout);
    > fflush(stdout);
    >

    Loops infinitely for persistent I/O error or EOF -- although this
    clearly is intended only to handle input from an interactive device
    like a keyboard, and keyboard EOF often (usually?) isn't sticky.
    (Also the message wording might be off for this case.)

    > /* Consume remaining line of input. */
    > while(0 != scanf("%*[^\n]"))
    > ;
    >

    Don't need while, just one call since %dftwidth[ = unbounded.
    (Like %s but unlike %c which defaults to 1.)

    > nfields = scanf("%d%1[^\n]", &num, dummy);
    > }
    >

    Personally I would either put the repeated scanf attempt in the while
    condition, or make this an n.5 loop explicitly (with break), rather
    than duplicating the code. But that's 'merely' style.

    > printf("num = %d\n", num);
    > }
    >

    <snip rest>
    David Thompson, Nov 16, 2010
    #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. Replies:
    4
    Views:
    655
    Walter Roberson
    Sep 9, 2005
  2. =?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,344
    those who know me have no need of my name
    Apr 3, 2006
  3. =?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:
    658
    Richard Bos
    May 2, 2006
  4. THTB
    Replies:
    0
    Views:
    173
  5. Max Williams
    Replies:
    3
    Views:
    157
    Robert Klemme
    Jan 6, 2009
Loading...

Share This Page