1

The problem of protecting the program in case of invalid input is as old as programming, and I've found many questions about that on this site, however nothing helped me in my case.

I've got a function which loads values into a float two-dimensional array.

void load_val(
                     float matrix[MAX_SIZE][MAX_SIZE],
                     const int line_num,
                     const int column_num
                     )
{
    for (int i=0; i<line_num; ++i)
    {
        printf("Give number\n");
        for (int j=0; j<column_num; ++j)
        {
            scanf("%f", &matrix[i][j]);
        }
    }

}

And obviously, when the user types in a letter, the program goes into an infinite loop. I used two solutions to that problem and neither worked. First one is using the fact that scanf returns 0 when there's invalid input.

So instead of

scanf("%f", &matrix[i][j]);

I wrote

while (scanf("%f", &matrix[i][j])==1);

But it still gives me an infinite loop.

The other solution was just using "isdigit" function.

int h = scanf("%f", &matrix[i][j]);
            if (isdigit(h)==0)
            {
                puts("INVALID");
                j--;
            }

but I really don't want to use other libraries and it also did not work. The problem seems to be that before I can even check if the input is valid, the program goes crazy because of the input.

I even tried this

float h;
if (scanf("%f", &h)==1)
       {
          matrix[i][j]=h;
       }
else
       {
          puts("INVALID");
          j--;
       };

Still - infinite loop. How can I check for invalid input in this loop-inside-a-loop before the program goes crazy?. Is the problem with the float type maybe?

2
  • 1
    use fgets to get the input in a string. Then parse the string to check for floats. If you get an unwanted character, you can skip it, or warn the user. Commented Nov 5, 2018 at 9:50
  • On an unrelated note, your use of isdigit is as wrong as it could possibly be. Especially since you seem to know what scanf returns. It's also a standard C function, so no "other libraries" will be used. Commented Nov 5, 2018 at 9:52

3 Answers 3

3

The problem is that when you give invalid input, then scanf doesn't remove it from the input buffer. Each time you call scanf in your loop, it will read the same input, over and over and over again.

Therefore it's usually recommended that you use fgets to read a whole line, and then use sscanf to parse that line.

And checking what scanf (or sscanf) returns is the correct way to check if it succeeded or not.

Sign up to request clarification or add additional context in comments.

Comments

2

fscanf():

For every conversion specifier other than n, the longest sequence of input characters which does not exceed any specified field width and which either is exactly what the conversion specifier expects or is a prefix of a sequence it would expect, is what's consumed from the stream. The first character, if any, after this consumed sequence remains unread. If the consumed sequence has length zero or if the consumed sequence cannot be converted as specified above, the matching failure occurs unless end-of-file, an encoding error, or a read error prevented input from the stream, in which case it is an input failure.

So if scanf() cannot use all (or any) characters, they remain in the input stream and the next scanf() will fail the same way the first one did, and so on.

To prevent that from happening you can read and discard characters from the input stream until you encounter a newline:

float value;
if(scanf("%f", value) != 1) {
    int ch;
    while((ch = getchar()) != EOF && ch != '\n');
}

Comments

1

If scanf encounters bytes that do no match the input format then those bytes will just be left on the input stream. Repeated calls to scanf will just get stuck at the same invalid characters. If you want to handle invalid input it's better to read all available input into a buffer (e.g. using fgets) and then use sscanf on the buffer, possibly in a loop so that you can advance the buffer pointer past invalid input. See https://stackoverflow.com/a/5969401/982257

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.