0

I want to write a code to ensure that the users input only 1 digit. If a user enters something like "0 1 3" I want my program to read an error message which I have no idea how to do. Anyone has an idea how to approach this? My current code just takes in the first number if a user enters bunch of numbers with a space in between.

Please see my code below. Thanks :D

//Prompt the user to enter the low radius with data validation
printf("Enter the low radius [0.0..40.0]: ");
do
{   
    ret = scanf("%lf", &lowRadius);
    //type validation
    if (ret != 1)
    {
        int ch = 0;
        while (((ch = getchar()) != EOF) && (ch != '\n'));
        printf("Wrong input. Please enter one numerical value: ");  
    }
    //range validation      
    else if((lowRadius < 0 || lowRadius > 40))
    {
        printf("Incorrect value. Please enter in range 0-40: ");
    }
    else break;
} while ((ret != 1) || (lowRadius < 0 || lowRadius > 40));//end while lowRadius
Joseph
  • 13
  • 3
  • 3
    You sort of have the code already. Use `getchar` to read from the input until the newline is found. If any non-white-space characters are before the newline, then the input was invalid. Also, you don't need the `do {} while` loop since you're using `break` anyways. A simple `while(1){}` or `for(;;){}` loop will work. Just `break` the loop when the input is valid. – user3386109 May 15 '16 at 19:45
  • That's because scanf is unsafe in many levels. See [this post](http://stackoverflow.com/questions/30577519/error-c4996-scanf-this-function-or-variable-may-be-unsafe-in-c-programming) about why is not recommended to use it, plus an alternative. Also you should consider using a external or 3rd part library to parse safely your inputs. – Joel May 15 '16 at 19:47
  • 2
    How are users to enter a value like `39` using a single digit? Do you mean 'a single number'? What about fractions (39.23423)? As you've already been told, it is probable that `scanf()` is not the tool; use `fgets()` to read a line and then maybe `sscanf()` or maybe `strtod()` to convert the value, handling error conditions carefully and check whether there's any debris after the number and before the newline. – Jonathan Leffler May 15 '16 at 19:58

3 Answers3

2

If you read the line into a string, then analyse it, you avoid the problem of hanging on unsupplied input. You have done most of the work already, but this shows how to trap too much input. It works by scanning a string after the double to pick up any more input. The return value from sscanf tells you if there was, because it returns the number of items successfully scanned.

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

void err(char *message)
{
    puts(message);
    exit(1);
}

int main(void)
{
    double lowRadius = 0.0;
    char inp[100];
    char more[2];
    int conv;
    if(fgets(inp, sizeof inp, stdin) == NULL) {
        err("Input unsuccesful");
    }
    conv = sscanf(inp, "%lf %1s", &lowRadius, more);  // conv is number of items scanned
    if(conv != 1) {
        err("One input value is required");
    }
    if(lowRadius < 0.0 || lowRadius > 40.0) {
        err("Number out of range");
    }
    printf("%f\n", lowRadius);
    return 0;
}

I'm unsure about your stipulation of a single digit, since that won't allow your maximum value to be entered.

Weather Vane
  • 31,226
  • 6
  • 28
  • 47
0

Read a whole line and convert it with strtod.

0

Alexander has the right approach, but doesn't give much detail. Here is how I would do it, using getline() to read the input, and then strspn() plus strtod() to parse the input that was read. If you are not familiar with working with pointers, this will be difficult to understand - but if you are learning C, you'll get there eventually:

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

int main(void) {
  double lowRadius;
  char *lineptr = NULL;
  size_t n;
  char *startptr;
  char *endptr;
  char *ws = " \t\n"; /* possible whitespace characters */

  printf("Enter the low radius [0.0..40.0]: ");

  while(1) {
    /* free lineptr if set - neeeded if we iterate on error input */
    if( lineptr ) {
      free(lineptr);
      lineptr = NULL;
    }

    /* now read a line of input */
    while( getline(&lineptr, &n, stdin) == -1 ) {
      /* error returned, just retry */
      continue;
    }

    /* skip over any leading whitespace */
    startptr = lineptr + strspn(lineptr,ws);

    /* Now try to convert double */
    lowRadius = strtod(startptr, &endptr);

    if( endptr==startptr || endptr[strspn(endptr,ws)] != 0 ) {
      /* either no characters were processed - e.g., the
         line was empty, or there was some non-whitespace
         character found after the number. */
      printf( "Wrong input.  Please enter one numerical value: ");
    } else if( (lowRadius < 0.0) || (lowRadius > 40.0) ) {
      printf( "Incorrect value. Please enter in range 0-40: " );
    } else {
      if( lineptr ) free(lineptr);
      break;
    }
  }
  printf( "value entered was %lf\n", lowRadius );
}
David McKinley
  • 1,833
  • 2
  • 9
  • 10