2017-01-29 10 views
2

사용자가 2 개 이하 또는 2 개 이하의 정수만 입력하길 원합니다. 또한 잘못된 입력시 오류를 인쇄하고 두 정수를 다시 입력하라는 메시지를 표시합니다. 사용자는 줄 바꿈이 아닌 공백으로 구분 된 두 개의 정수를 입력해야합니다. 따라서, 예를 들어 :
1) 유효 입력된다 : 1 2
2)가 잘못 입력 1
3) 잘못 입력 :사용자가 C에서 필요로하는 것보다 더 많은 또는 적은 입력을 입력하는 것을 방지하려면 어떻게해야합니까?

#include<stdio.h> 

int main(){ 

    int first; 
    int second; 
    printf("Enter input:\n"); 
    int returnValue = scanf("%d %d", &first, &second); 
    while(returnValue != 2){ 
     printf("Invalid input. Please enter again: \n"); 
     returnValue = scanf("%d %d", &first, &second); 
    } 
    printf("First: %d Second: %d\n", first, second); 
    return 0; 
} 
: 1 2 3

I는 두 가지 방식에 따라 그것을 시도

scanf가 관련된이 첫 번째 접근 방식에서는 사용자가 개행에서 각 정수를 입력하지 못하게했습니다. 어느 쪽도 입력을 단지 2 개의 숫자로 제한 할 수 없다. 즉, 사용자가 2 이상의 정수를 입력하면 프로그램은 처음 2 정수를 허용하고 3 정수를 무시합니다. 이 경우 오류를 인쇄하고 싶습니다.

내 다른 접근 방식이는 fgets와 sscanf를 포함한다 :이 방법에서

#include<stdio.h> 

int main(){ 

    int first; 
    int second; 
    printf("Enter input:\n"); 
    char line[20]; 
    fgets(line, sizeof(line), stdin); 
    int returnValue = sscanf(line, "%d %d", &first, &second); 

    while(returnValue != 2){ 
    printf("Invalid input. Please enter again: \n"); 
    fgets(line, sizeof(line), stdin); 
    returnValue = sscanf(line, "%d %d", &first, &second); 
    } 

    printf("First: %d Second: %d\n", first, second); 
    return 0; 
} 

을, 나는 사용자 안타는 단 하나의 정수를 입력 한 후 입력하면 오류를 인쇄 할 수 있어요. 그러나 입력을 단지 2 개의 숫자로 제한 할 수는 없습니다. 즉, 사용자가 2 이상의 정수를 입력하면 프로그램은 처음 2 정수를 허용하고 3 정수를 무시합니다. 이 경우 오류를 인쇄하고 싶습니다.

제 질문은 첫 번째 접근 방식과 두 번째 접근 방식을 수정하여 내 요구 사항을 달성 할 수 있습니까?

감사합니다.

+2

하드웨어 지원이 없으면 (예 : 모든 글자가 비활성화 된 키보드, 문자 A를 치면 사용자를 전기 방식으로 전환하는 등) 사용자가 선택한 입력을 금지 할 수 없습니다. 당신이 할 수있는 대부분은 입력을 받아들이고 그것을 확인하는 것입니다. 잘못된 입력이 발생하면 잘못된 부분을 무시하거나 데이터 블록을 무시하거나 (예 : 잘못된 입력이있는 경우 전체 행) 무시하거나 단순히 입력을 버리고 사용자가 유효한 내용을 입력 할 때까지 계속 묻습니다. – Peter

+1

"제 질문은 첫 번째 접근 방식과 두 번째 접근 방식을 수정하여 내 요구 사항을 달성 할 수 있습니까?" -> 예, [예] (http://stackoverflow.com/a/27805565/2410359)하지만 그만한 가치는 없습니다. [@ David Bowling] (http://stackoverflow.com/a/41917246/2410359) – chux

답변

3

하나의 솔루션가 될 것이다 : 당신의 주요 기능에

int secure_input(int max, int min) { 
    int choice,buffer; 
    do { 
     choice = -1;//initialize in a values not included among min and max 
     scanf("%d", &choice); 
     while ((buffer = getchar()) != '\n' ? buffer != EOF : false); // empty the buffer to avoid infinite loop 
    } while (choice > max ? true : choice < min); 
    return choice; 
} 

를 방금 같은 함수를 호출하는 %d 두 번 전환 후 %n 변환 사양을 사용하십시오. %n 변환 지정은 문자와 일치하지 않지만이 시점까지 읽은 문자 수를 형식 문자열에 저장합니다. 그래서, 호출 : 두 번째 %d 경우

sscanf(line, "%d %d %n", &first, &second, &bufPos); 

에 도달 할 때, 다음 bufPosline에서 마지막으로 읽은 문자 다음의 문자의 인덱스를 개최한다. %n 앞에 공백이 있기 때문에 인덱스 값이 bufPos에 저장되기 전에 0 개 이상의 공백 문자를 읽고 건너 뜁니다. 따라서 유효한 항목 뒤에 bufPos\0 종결자를 나타냅니다. 이 색인에 line에 다른 문자가 있으면 입력에 관련없는 문자가 있습니다.

다음은 두 번째 코드 예제를 수정 한 것입니다. fgets()이 입력 행을 읽은 후 sscanf()은 문자열을 스캔하는 데 사용됩니다. 일치하는 항목이 2 개 미만이거나 이 '\0'이 아닌 경우 badInputtrue으로 설정됩니다.입력 루프는 do 루프이며 한 번 실행되고 badInputtrue 일 때까지 계속 실행됩니다.

#include <stdio.h> 
#include <stdlib.h>     // for exit() 
#include <stdbool.h>    // for bool type 

#define BUF_SIZE 100 

int main(void) 
{ 
    int first; 
    int second; 
    char line[BUF_SIZE]; 
    int returnValue; 
    int bufPos; 
    bool badInput = false; 

    do { 
     if (badInput) { 
      printf("Invalid input. Please enter again: "); 
      badInput = false; 
     } else { 
      printf("Enter input: "); 
     } 
     if (fgets(line, sizeof(line), stdin) == NULL) { 
      perror("Error in fgets()"); 
      exit(EXIT_FAILURE); 
     } 

     returnValue = sscanf(line, "%d %d %n", &first, &second, &bufPos); 

     if (returnValue < 2 || line[bufPos] != '\0') { 
      badInput = true; 
     } 

    } while (badInput); 

    printf("First: %d Second: %d\n", first, second); 

    return 0; 
} 

샘플 상호 작용 : 다른 답변에서

Enter input: 1 
Invalid input. Please enter again: 1 2 3 
Invalid input. Please enter again: 
Invalid input. Please enter again: 1 2 
First: 1 Second: 2 
+0

이것은 효과가 있습니다. 감사! –

1

char *을 묻는 질문을 피하려면 regular expression을 사용할 수 있습니다. 당신이이 기능을 사용할 수있는 하나의 scanf 두를 얻기 위해 강제하지 않는 경우 :

first = secure_input(2;1); 
+0

희소 한 입력 오류에'choice'의 가치는'-1'일지도 모르고 다. 'scanf()'의 리턴 값을 테스트하는 것이 더 좋다. 'buffer = (char) getchar()'에서'char'로 변환하면 end-of-file이 발생하고'char'가 unsigned 일 때 무한 루프가됩니다. int 버퍼를 사용하고 캐스팅을 드롭하는 것이 가장 좋습니다. – chux

0

다른, 당신은 또한 다음 많은 숫자가 발견 된 방법 확인, strtok()를 사용하여 입력을 구문 분석 할 수있다. 이 방법은 복잡하지만 문제에 대한 다른 시각을 제공합니다. 단지 2가 발견 된 경우 while() 루프 내부

, 당신은, 다음, fgets()에서 발견 얼마나 많은 간격 번호를 확인하실 수 있습니다 다음 수 break 루프 중. 그렇지 않으면 계속 검색하십시오. 루프에서 벗어나면 sscanf()의 가장 최근 입력에서 두 개의 정수를 읽을 수 있습니다. strtol()을 사용하여 정수가 유효한지 확인할 수도 있습니다.

참고 :strtok()은 reeantrant이며 구문 분석하는 문자열을 수정합니다. 따라서이 경우 어딘가에 복사본을 만들어야 할 수 있습니다. 이 작업을 수행하려면 strdup() 또는 malloc()을 사용할 수 있습니다.

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

#define LINESIZE 20 
#define BASE 10 

int main(void) { 
    char line[LINESIZE]; 
    const int n = LINESIZE; 

    char *number, *copy, *endptr; 
    const char *delim = " "; 

    int first, second, check, invalidnum; 
    size_t slen, count; 

    while (1) { 
     printf("Enter input: "); 
     if (fgets(line, n, stdin) == NULL) { 
      printf("Error reading buffer from fgets()\n"); 
      exit(EXIT_FAILURE); 
     } 

     slen = strlen(line); 
     if (slen > 0 && line[slen-1] == '\n') { 
      line[slen-1] = '\0'; 
     } else { 
      printf("Buffer overflow detected\n"); 
      exit(EXIT_FAILURE); 
     } 

     copy = strdup(line); 

     count = 0; 
     invalidnum = 0; 
     number = strtok(copy, delim); 
     while (number != NULL) { 
      check = strtol(number, &endptr, BASE); 
      if (endptr == number || check == 0) { 
       invalidnum = 1; 
       break; 
      } 
      count++; 
      number = strtok(NULL, delim); 
     } 
     free(copy); 
     copy = NULL; 

     if (count != 2 || invalidnum) { 
      printf("Invalid input\n\n"); 
     } else { 
      break; 
     } 
    } 

    if (sscanf(line, "%d %d", &first, &second) != 2) { 
     printf("Unexpected error from sscanf()\n"); 
     exit(EXIT_FAILURE); 
    } 
    printf("first = %d, second = %d\n", first, second); 

    return 0; 
} 

이이 문제에 대한 또 다른 접근 방식입니다 : 여기

이 표시 몇 가지 예제 코드입니다. 단순성 측면에서 @David Bowling은 더 좋은 아이디어를 가지고 있으며, 나는 그를 사용하라고 제안합니다.