0

I've run into a problem that, oddly enough, I can't solve. It is necessary for the user to prohibit the input of letters and any other characters that are not related to numbers. That is, the usual check whether it is a number or not a number, and in case of incorrect data entry, return the user back to the input. Who is not difficult, please tell me how to implement in my program. Here is a snippet of the program.

int main() {

    int n, m;

    printf("Enter the number of planned measurements for the variance count and math. expectations taking into account the statistical outlier: ");
    scanf_s("%d", &n);

    if (!isdigit(n)) {
         printf("\nYou can only enter letters!\n");
         printf("Enter the data correctly: ");
         scanf_s("%d", &n);
    }
    printf("Enter the number of planned measurements for the variance count and math. expectations: ");
    scanf_s("%d", &m);
    printf("===================================================\n");
    printf("Enter your measurements for the variance count and math. expectations taking into account the statistical outlier: ");
}

Used isdigit() but didn't work.

if (!isdigit(n)) {
     printf("\nYou can only enter letters!\n");
     printf("Enter the data correctly: ");
     scanf_s("%d", &n);
}

and

while (int n = (int)_getch()){
    if (isdigit(n)){
        cout << n;
    }
}
Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
Opus
  • 23
  • 2
  • 3
    First of all, stop using ```scanf``` for user input. – Harith Jan 20 '23 at 06:28
  • 1
    Secondly, ```scanf``` returns the number of elements it was able to process and convert successfully. Your code should check for it. – Harith Jan 20 '23 at 06:28
  • Thirdly, ```scanf``` would consider ```123abj``` as a valid number and leave ```abj``` in the input buffer. – Harith Jan 20 '23 at 06:29
  • Moreover, it would also consider ```6493.2039``` with the ```%d``` specifier valid. – Harith Jan 20 '23 at 06:34
  • It looks like you are using c, not c++. If you request a c solution, remove the c++ tag. – zdf Jan 20 '23 at 06:38
  • C with `cout` was invalidly used. – 273K Jan 20 '23 at 06:40
  • 6
    Unless you have dedicated hardware support (like a system that detects the user's finger approaching a wrong key on a keyboard, and preemptively electrocutes the user) there is no way to prevent the user from entering bad characters. You need to read all input, and then check that input and possibly discard bad input. `scanf()` doesn't do that - it detects bad input, but does not discard it (so multiple calls of `scanf()` can keep receiving the same bad data). Instead, try reading all input as (say) a string, and then parse the string while ignoring or discarding bad characters. – Peter Jan 20 '23 at 06:41
  • Also In C++ use [std::format](https://en.cppreference.com/w/cpp/utility/format/format) instead of printf – Pepijn Kramer Jan 20 '23 at 06:45
  • 1
    (1) `isdigit` checks for a single digit, not a whole number. (2) You can use `fgets()` function to get the full line of input and then use the `strtol()` function to read a long integer from a string. This function will convert the initial portion of the string, which contains a valid integer representation, to a long integer, and it will return a pointer to the first invalid character. (3) If the user enters any non-numeric characters, the `scanf()` function will stop reading and leave those characters in the input buffer. – zdf Jan 20 '23 at 06:52
  • 2
    You will need to check the result of scanf to see if it succeeded. Other than that, it is a more rugged solution to use `fgets` and read everything as a string, then parse that string. – Lundin Jan 20 '23 at 07:55
  • Thanks for the answers, but I'm not strong in programming and just started learning C. Please write a code or an example of how it should look in my program. – Opus Jan 20 '23 at 08:07
  • 1
    There are already too many questions pertaining to ```fgets, strtol, and sscanf```. Search. :) – Harith Jan 20 '23 at 08:37
  • @PepijnKramer the question is about C, not C++. – Jabberwocky Jan 20 '23 at 08:38
  • @Jabberwocky It still had C++ tag earlier ;) Removed my feedback – Pepijn Kramer Jan 20 '23 at 08:54
  • @Opus If you are at the beginning stage where `scanf` seems like the easiest way to do input, then — please don't take this the wrong way, I don't mean it as a criticism — you are probably simply not ready to solve this problem. Rejecting bad input is surprisingly hard. Was it an assignment you gave yourself, or that someone gave you and you must solve? See [What can I use for input conversion instead of `scanf`?](https://stackoverflow.com/questions/58403537) See also [A beginners' guide *away from* `scanf()`](http://sekrit.de/webdocs/c/beginners-guide-away-from-scanf.html). – Steve Summit Jan 20 '23 at 13:31

1 Answers1

2

Code cannot prevent a user from typing. Instead read a line of input as text and parse it for acceptability.

Use fgets() to read a line of user input and save into a string.
The key is to separate reading data from data parsing/validation.

Consider a basic helper function:

int get_int(const char *prompt, const char *reprompt) {
  char buf[100];
  for (;;) {
    fputs(prompt, stdout);
    if (fgets(buf, sizeof buf, stdin) == NULL) {
      fprintf(stderr, "Standard input closed.\n");
      exit(EXIT_FAILURE);
    }
    int n;
    // scanf_s("%d", &n);
    if (sscanf(buf, "%d", &n) == 1) {  // See also strtol()
      return n;
    }
    prompt = reprompt;
  }
}

Later on we can improve:

  • Detect out of range values. (Use strtol())

  • Detect extra junk after the numeric input.

  • Handle overly long lines.

  • Limit range to a sub-range of int if needed.

  • More gracefully handle end-of-file.

  • etc.

Use:

const char *p1 = "Enter the number of planned measurements for the variance count and math. expectations taking into account the statistical outlier: ";
const char *p2 = "Enter the number of planned measurements for the variance count and math. expectations: ";
const char *oops = "\nYou can only enter letters!\n" "Enter the data correctly: ";

n = get_int(p1, oops);
m = get_int(p2, oops);

Avoid scanf_s() and scanf() until you understand why they are bad.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256