Jak zeskanować tylko liczbę całkowitą i powtórzyć odczyt, jeśli użytkownik wprowadzi znaki inne niż numeryczne?

Oto mały problem młodego tyro z kodem C, który próbuje po prostu uniemożliwić użytkownikowi wpisanie znaku lub liczby całkowitej mniejszej niż 0 lub większej niż 23.

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

int main(void)
{
    const char *input;
    char *iPtr;
    int count = 0;
    int rows;

    printf("Enter an integer: ");
    scanf("%s", input);
    rows = strtol(input, &iPtr, 0);
    while( *iPtr != '\0') // Check if any character has been inserted
    {
        printf("Enter an integer between 1 and 23: ");
        scanf("%s", input);
    }
    while(0 < rows && rows < 24) // check if the user input is within the boundaries
    {
        printf("Select an integer from 1 to 23: ");
        scanf("%s", input);
    }  
    while (count != rows)  
    {  
        /* Do some stuff */  
    }  
    return 0;  
}
Udało mi się w połowie i mały push up będzie mile widziany.
Author: 7kemZmani, 2012-12-31

6 answers

Użyj scanf("%d",&rows) zamiast scanf("%s",input)

To pozwala uzyskać bezpośrednio wartość całkowitą ze standardowego wejścia bez konieczności konwersji na int.

Jeśli użytkownik wprowadzi łańcuch zawierający znaki inne niż numeryczne, musisz wyczyścić swój stdin przed następnym scanf("%d",&rows).

Twój kod może wyglądać tak:

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

int clean_stdin()
{
    while (getchar()!='\n');
    return 1;
}

int main(void)  
{ 
    int rows =0;  
    char c;
    do
    {  
        printf("\nEnter an integer from 1 to 23: ");

    } while (((scanf("%d%c", &rows, &c)!=2 || c!='\n') && clean_stdin()) || rows<1 || rows>23);

    return 0;  
}

Wyjaśnienie

1)

scanf("%d%c", &rows, &c)

Oznacza to oczekiwanie od użytkownika wprowadzenia liczby całkowitej, a w pobliżu niej nieliczbowej charakter.

Przykład1: Jeśli użytkownik wprowadzi aaddk, a następnie ENTER, scanf zwróci 0. Nothing capted

Przykład2: jeśli użytkownik wprowadzi 45, a następnie ENTER, scanf zwróci 2 (2 elementy są podpisane). Tutaj %d jest capting 45 i %c jest capting \n

Przykład3: jeśli użytkownik wprowadzi 45aaadd, a następnie ENTER, scanf zwróci 2 (2 elementy są podpisane). Tutaj {[11] } jest capting 45 i %c jest capting a

2)

(scanf("%d%c", &rows, &c)!=2 || c!='\n')

w przykładzie 1: warunek ten jest TRUE ponieważ scanf zwraca 0 (!=2)

w przykładzie 2: warunek ten jest FALSE, ponieważ scanf zwraca 2 i c == '\n'

w przykładzie 3: warunek ten jest TRUE, ponieważ scanf zwraca 2 i c == 'a' (!='\n')

3)

((scanf("%d%c", &rows, &c)!=2 || c!='\n') && clean_stdin())

clean_stdin() jest zawsze TRUE ponieważ funkcja zwraca zawsze 1

w przykładzie 1: (scanf("%d%c", &rows, &c)!=2 || c!='\n') jest TRUE więc warunek po && powinien być sprawdzony, więc clean_stdin() zostanie wykonany, a cały warunek to TRUE

w przykładzie 2: (scanf("%d%c", &rows, &c)!=2 || c!='\n') jest FALSE, więc warunek po && nie będzie sprawdzany (ponieważ jego wynikiem będzie cały warunek będzie FALSE), więc clean_stdin() nie będzie wykonywany, a cały warunek będzie FALSE

w przykład3: (scanf("%d%c", &rows, &c)!=2 || c!='\n') jest TRUE więc warunek po && powinien być sprawdzony, więc clean_stdin() zostanie wykonany, a cały warunek to TRUE

Można więc zauważyć, że clean_stdin() zostanie wykonane tylko wtedy, gdy użytkownik wprowadzi ciąg zawierający znak nieliczbowy.

I ten warunek ((scanf("%d%c", &rows, &c)!=2 || c!='\n') && clean_stdin()) zwróci FALSE tylko wtedy, gdy użytkownik wprowadzi integer i nic więcej

I jeśli warunek ((scanf("%d%c", &rows, &c)!=2 || c!='\n') && clean_stdin()) jest FALSE, A integer jest pomiędzy i 1 i 23, to pętla while zostanie przerwana w przeciwnym razie pętla while będzie kontynuowana

 32
Author: MOHAMED,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-29 07:37:53
#include <stdio.h>
main()
{
    char str[100];
    int num;
    while(1) {
        printf("Enter a number: ");
        scanf("%[^0-9]%d",str,&num);
        printf("You entered the number %d\n",num);
    }
    return 0;
}

%[^0-9] w scanf() pożera wszystko, co nie jest pomiędzy 0 A 9. Zasadniczo czyści strumień wejściowy z niecyfrów i umieszcza go w str. Długość sekwencji niecyfrowej jest ograniczona do 100. Poniższy %d wybiera tylko liczby całkowite w strumieniu wejściowym i umieszcza je w num.

 2
Author: Swathyprabhu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-22 11:20:29

Można utworzyć funkcję, która odczytuje liczbę całkowitą między 1 A 23 lub zwraca 0, jeśli nie-int

Np.

int getInt()
{
  int n = 0;
  char buffer[128];
  fgets(buffer,sizeof(buffer),stdin);
  n = atoi(buffer); 
  return ( n > 23 || n < 1 ) ? 0 : n;
}
 1
Author: Anders,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-31 10:13:42

Musisz powtórzyć połączenie do strtol wewnątrz pętli, w której prosisz użytkownika, aby spróbował ponownie. W rzeczywistości, jeśli zrobisz pętlę do { ... } while(...); zamiast while, nie otrzymasz tego samego rodzaju powtarzania rzeczy dwa razy.

Powinieneś również sformatować swój kod tak, aby można było zobaczyć, gdzie kod znajduje się w pętli, a nie.

 0
Author: Mats Petersson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-31 08:55:11

MOHAMED, Twoja odpowiedź jest świetna i naprawdę mi pomogła. Tutaj zamieściłem kod, który moim zdaniem jest nieco prostszy:

#include <stdio.h>

int getPositive(void);
void clean_input(void);

int main(void) {
     printf("%d\n",getPositive());

     return 0;
}



int getPositive(void) {
    int number;
    char buffer;  // Holds last character from user input. 
                  // (i.e '\n' or any other character besides numbers)
    int flag;     // Holds scanf return value

    do{ 
        flag = scanf("%d%c", &number, &buffer); // Gets input from user

        // While scanf did not read 2 objects (i.e 1 int & 1 char)
        // or the user inputed a number and then a character (eg. 12te)
        // ask user to type a valid value

        while (flag !=2 || buffer!='\n') {

            clean_input();
            printf("%s","You have typed non numeric characters.\n"
                    "Please type an integer\n?");
            flag = scanf("%d%c", &number, &buffer);
        }

        if(number<0) {
            printf("%s","You have typed a non positive integer\n"
                    "Please type a positive integer\n?");

        } else {     // If user typed a non negative value, exit do-while.
              break;
        }

    }while(1);
}

void clean_input(void) {
    while (getchar()!='\n');
    return;
}

W moim przypadku chcę, aby liczba była tylko dodatnia. Jeśli chcesz, aby Twoja liczba wynosiła od 1 do 23, zamień number<0 na number<1 || number>23 w instrukcji if . Musisz również zmienić printf, aby wydrukować odpowiednią wiadomość.

 0
Author: Elefther,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-09 13:03:54
char check1[10], check2[10];
int foo;

do{
  printf(">> ");
  scanf(" %s", check1);
  foo = strtol(check1, NULL, 10); // convert the string to decimal number
  sprintf(check2, "%d", foo); // re-convert "foo" to string for comparison
} while (!(strcmp(check1, check2) == 0 && 0 < foo && foo < 24)); // repeat if the input is not number

Jeśli dane wejściowe są number, możesz użyć foo jako danych wejściowych.

 0
Author: Yonggoo Noh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-04 02:41:49