Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.0k views
in Technique[技术] by (71.8m points)

c - How do I limit the input of scanf to integers and floats (numbers in general)

I am curently learning C Programming in University and I got the task to write a program witch puts out the interception points with 0 / x-axis of any function ax^2+bx+c.

In order to make sure that the input is correct (int, float, etc.) I run the following while loop. Prior to that a is definded as a double.

printf("Input for a=");

while (scanf("%lf", &a) == 0)
{
    fflush(stdin);
    scanf("%lf", &a);
    printf("Incorrect Input! New Input needed.
"); 
    printf("a=");
}

I am aware that the fflush(stdin) operator only clears the buffer when a second input function occurs and therefore the fflush inside the loop does not clear the buffer and therefore the condition of the loop is always true and thus I created an infinite loop.

My professor also forbids the use of goto, which is why I am here, because I can't come up with a reasonable solution that solves this problem. I also tried and failed with:

do
{
    printf("
Input for a= ");
    scanf("%lf", &a);
}

while (isdigit(a));
{
    printf("Thank you.
");
}

With this arrangement I get the failure notification: Expression c >= -1 && <= 255. I guess this has to do with false variable definition (double, digit) or such.

However my original question was whether there is an elegant solution to this problem or at least any solution.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Lukas, I'm still not 100% clear and your:

"Im am asking how to distinguish between all numbers and every other possible input for scanf."

scanf can provide conversion to a single given type based on the conversion specifier used, so you can't read both int and float with the same scanf statement and a single conversion specifier. (now you can read a line with, e.g. fgets and then use alternate sscanf statements and check the remaining characters to do that)

That said, I think I understand what you are asking and can answer both the fflush and read of a value questions.

To begin, when using scanf you must check the return and handle three-cases. (1) EOF, the user cancels input with a Ctrl+d (or Ctrl+z on windows); (2) a matching or input failure occurs resulting in a return of less than the number of conversion specifiers used; and finally (3) the good input case (where you impose any additional checks you have, e.g. positive, less than 100, etc..)

While fflush(stdin) is undefined behavior on most systems, there are a number of implementations that allow it. (primarily windows, but Linux allows it for seekable stream, e.g. a file redirected on stdin) Bottom line, it isn't portable without caveats, so it's best to provide a simple equivalent with getchar(), e.g.

void empty_stdin (void)
{
    int c = getchar();

    while (c != '
' && c != EOF)
        c = getchar();
}

As for scanf, as I mentioned in the comment, it is far easier to enclose the scanf call within an infinite loop which you only break when the input satisfies all your constraints. A simple example requiring integer input would be:

int getint (int *value, const char *prompt)
{
    /* loop continually until good input or canceled */
    for (;;) {
        int rtn;
        fputs (prompt, stdout);     /* display prompt */
        rtn = scanf ("%d", value);

        if (rtn == EOF) {   /* user generated manual EOF */
            fputs ("<user canceled input>
", stderr);
            return 0;
        }
        empty_stdin();  /* all other cases - empty input buffer */
        if (rtn == 1)   /* good input, break */
            break;
        /* otherwise matching failure */
        fputs ("  error: invalid integer input.
", stderr);
    }
    return *value;  /* value also availale through pointer */
}

Putting it altogether in a simple example, you would have:

#include <stdio.h>

void empty_stdin (void)
{
    int c = getchar();

    while (c != '
' && c != EOF)
        c = getchar();
}

int getint (int *value, const char *prompt)
{
    /* loop continually until good input or canceled */
    for (;;) {
        int rtn;
        fputs (prompt, stdout);     /* display prompt */
        rtn = scanf ("%d", value);

        if (rtn == EOF) {   /* user generated manual EOF */
            fputs ("<user canceled input>
", stderr);
            return 0;
        }
        empty_stdin();  /* all other cases - empty input buffer */
        if (rtn == 1)   /* good input, break */
            break;
        /* otherwise matching failure */
        fputs ("  error: invalid integer input.
", stderr);
    }
    return *value;  /* value also availale through pointer */
}

int main (void) {

    int v,
        i = getint (&v, "enter integer value: ");

    if (i)
        printf ("
integer: %d
", v);

    return 0;
}

Example Use/Output

Where you can now do your best to break any input routine you write. If you find a problem, go fix it and try to break it again.

The code above allows for fairly robust input of any one given type of value, e.g.

$ ./bin/scanfint
enter integer value: no
  error: invalid integer input.
enter integer value: apples, banannas, and pears
  error: invalid integer input.
enter integer value: 21

integer: 21

Look things over and let me know if your question was slightly different, or if you have further questions about the answer.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...