0

Let's say I am creating a 3*4 matrix (or a 2D array of 12 elements). So I want user to enter values of elements one by one as a sequence, divided by either spaces/tabs or enter-key. Also, if a value in a sequence is bad (in my case, any non-integer values are bad), I want to ignore it and read next values until I have all 12 of them.

int fill(Matrix * mtx)
{
    puts("Start entering numbers. Please note that only integer values will be recorded.");

    int temp = 0;

    for (int i = 1; i <= mtx -> rows; i++)
    {
        for (int j = 1; j <= mtx -> cols; j++)
        {
            scanf(" %d", &temp);

            setElement(mtx, i, j, temp);
        }
    }

    return 0;
}

This is my most basic vision of the algorithm; I was wondering about the implementation of this "skip input if bad" condition.

Just started learning C btw, so any kind of advice is hugely appreciated!

1
  • 1
    Read the input into strings. Use strtol() to convert it to a number, and its return value can be used to detect if it's valid. Commented Jan 26, 2018 at 3:33

2 Answers 2

2

You have to check the return value of scanf to be sure whether it scanned the integer input correctly or not. In case it fails due to some bad input - scanf can't take that as input and then you have to make sure that you clear the stdin so that the next calls of scanf don't fail. What you can do is, when scanf returns 0 - consume all characters (using getchar or similar) and do this until you get \n (Considering that user inputs the number each in a line). Illustration would be:

int n; //total number inputs to take.
n = 10;
int num, num_inputs = 0; 
while( 1 )
{
   while(scanf("%d", &num) != 1)
   {
       int c;
       while ((c = getchar()) != EOF && c != '\n')
          ;
       if(c == EOF){ fprintf(stderr,"Error in input\n"); exit(1)} 
   }
   num_inputs++; // one more int correctly input.
   ...
   if( num_inputs == n )
      break;
}

An alternative and better way would be to use strto* functions and then considering the return value of it to understand whether there is any error or not. Illustration would be: (Here we have shown just the case where there is single int input in each line - this can be extended to process multiple int inputs in a line).

char buf[MAXLEN];
int num_inputs = 0;
while(fgets(buf,MAXLEN,stdin)){
    char *en;
    errno = 0;
    long n = strtol(line, &en, 10);
    if (errno == 0 && *en== '\0' && n >= INT_MIN && n < INT_MAX)
    {
        // n is an correctly inputted int
        num_inputs++;
    }
}

Check the man page for strtol - there is a detailed listing of the erros one might get. Check it.

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

Comments

2

Check what scanf returns. If not 1 means entered value is not a digit in this case. So discard the data from the stream first before entering next data.

int fill(Matrix * mtx) {
    puts("Start entering numbers. Please note that only integer values will be recorded."); 
    int temp = 0, v; 
    for (int i = 1; i <= mtx->rows; i++) {
        for (int j = 1; j <= mtx->cols; j++) {
            v = scanf(" %d", &temp); 
            if (v != 1) {  //if invalid input.
                while ( (v = getchar()) != EOF && v != '\n' );  // discard invalid input.
                j--;  //don't forget to `j--` or else you will skip one position.
            }
            else {  // if correct input.
                setElement(mtx, i, j, temp); 
            }
        } 
    }
    return 0;
}

2 Comments

Note that the dot . and arrow -> operators bind very tightly and should never have spaces around them.
Ok, didn't know that one. Thank you for pointing that out. :) See edited.

Your Answer

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