본문 바로가기

컴퓨터/C

scanf에서 값을 받아들이지 못하고 스킵될 때

출처 : http://itguru.tistory.com/36


게시글 삭제 혹은 블로그 폐쇠 방지를 위해 해당 부분만 스크랩.


 scanf 함수의 고질적인 문제 및 해결책
 

scanf 함수를 사용하다 보면 다음과 같이 입력을 받지 않고 넘어가는 경우가 종종 있다.

    printf("숫자를 입력하세요 : ");
    scanf("%d", &num);

    printf("문자를 입력하세요 : ");
    scanf("%c", &c);

로 하면 "문자를 입력하세요 : " 부분이 실행되지 않고 넘어간다. 
이러한 일이 발생하는 원인과 해결책은 여기를 누르면 알 수 있다. 이 글에 제시된 해결책 보다 조금 높은 수준을 원한다면 * 문자를 활용하면 된다. 앞에서 말했듯이 * 문자는 stdin 에서 입력은 받지만 그 데이터는 버려버리는 특징을 이용하면

scanf("%d", &num);
scanf("%*c%c", &c);

와 같이 하면 된다. 왜냐하면 "%*c%c" 라는 형식 문자열의 의미는 "stdin 에서 한 문자를 얻어오되 그 값은 버리고 (이 경우 \n 이 버려진다), 그 다음에 한 문자를 얻어와 이에 대응되는 인자 (&c) 에 저장한다" 이기 때문이다. 

하지만 이러한 문제를 가장 잘 해결하는 방법은 fgets 함수를 이용하는 것이다. 

  scanf 함수 사용시 주의할 점
 

scanf 함수는 문자열 입력시 입력받을 문자열의 최대 개수를 제한을 두지 않으므로 버퍼 오버플로우가 발생할 여지가 충분히 있다. 이를 해결하기 위해서는 역시 fgets 함수를 이용하거나 폭을 지정해 주면 된다. 예를 들어서

char str[10];
scanf("%9s", str);

와 같이 한다면 우리가 stdin 에 아무리 많이 입력해도 scanf 는 오직 9 문자만을 취하므로 안전하게 입력이 가능하다. (배열의 크기는 10 이지만 NULL 문자를 위해서 9 자만 입력해야 한다) 하지만 이와 같이 할 경우에도 문제가 있는데, 사용자가 9 문자 보다 많이 입력했을 경우 scanf 는 오직 9 문자만을 처리하므로 일부 문자가 버퍼에 남아 있어서 다음번 입력 시 차질이 생긴다. 이는 다음과 같이 해결 할 수 있다.

scanf("%9s%*s", str);

왜냐하면 처음 %9s 를 통해서 9 문자만 입력 받고 stdin 에 남아있는 나머지 문자열들은 %*s 가 날려버리기 때문이다. 

  실행 예제
 

/* 각 형식에 맞는 입력을 받은 뒤 이를 출력한다.*/
#include <stdio.h>
int main()
{
    char str[10];
    char ch;
    int dec, hex, oct;
    float db;

    printf("문자열, 문자, 십진수, 16 진수, 8 진수, 소수를 각각 입력하세요\n");
    scanf("%9s %*s %c %d %x %o %f", str, &ch, &dec, &hex, &oct, &db);

    printf("문자열 : %s \n", str);
    printf("문자 : %c \n", ch);
    printf("십진수 : %d \n", dec);
    printf("16 진수 : %x \n", hex);
    printf("8 진수 : %o \n", oct);
    printf("소수 : %f \n", db);
    return 0;
}

실행 결과