scanf("%c")의 문제

MTTW·2021년 4월 2일
2

C++

목록 보기
4/4

이 게시물은 우리 랩실의 착한 석사 언니의 질문으로부터 시작되었다.
C언어 과제 채점 중 이상한 오류로 질문이 쏟아지는데 원인이 뭐냐는 질문이었다. 사실 처음에 보고 나도 왜 그런지 몰랐다. 그래도 코테 언어를 C++을 쓰는데 이런 자잘한 부분을 짚고 넘어가는게 좋을 것 같고, 나도 궁금해서 글로 남긴다.


scanf("%c")의 문제

백문이 불여일견 코드로 보자.

int main(){
    char input[5];

    while(true){
        printf("enter: ");
        scanf("%c", &input);
    }

    return 0;
}

char 문자 하나를 받는 간단한 코드다. 하지만 이렇게 입력을 받은 결과 문제가 발생한다.

❓ 왜 while문을 맘대로 한바퀴 더 돌아버린거지? 하지만 같은 코드로 int형 변수를 입력 받을 때는 이런 문제가 발생하지 않는다.

int main(){
    int input;

    while(true){
        printf("enter: ");
        scanf("%d", &input);
    }
    
    return 0;
}

그렇다면 왜 scanf("%c")를 실행할 때만 이런 문제가 생기는 걸까

요약하자면 개행 문자 때문에 그렇다.


원인

개행 문자
new line character의 약어. 인자 또는 표시의 위치를 다음 행의 최초의 위치로 이동시키는 서식 제어 문자. 즉, 인자 위치나 표시 위치를 다음의 인자 행이나 표시 행의 최초의 장소로 이동시키기 위한 서식 제어 문자.

쉽게 말하면 \n다.

키보드 입력은 모두 입력 버퍼에 담긴다. scanf는 입력버퍼에서 명령 받은 대로 받아오는 셈이다.

위의 예시로 설명하자면 우리가 입력한 "A\n"가 담기고 scanf는 문자열 하나씩 읽어온다. while문의 첫 바퀴에서는 "A"를 읽고 그 다음 바퀴에는 "\n"를 읽는다.


그럼 scanf("%d")는 왜 말짱해?
당연히 %dint형을 받아올 것을 명시했기 때문에 입력버퍼에 "\n"는 읽지 않는다. 입력버퍼에 담기는 것은 동일하다.

그렇다면 아래 코드와 같은 경우는 어떻게 될지 예상해볼 수 있다.

int main(){
    int _int;
    char _char[5];

    while(true){
        printf("enter int: ");
        scanf("%d", &_int);
        printf("enter char :");
        scanf("%c", &_char);
    }

    return 0;
}

숫자 + 개행문자가 입력버퍼에 들어갈 것이기 때문에 두 번째 scanf("%c")는 개행문자를 받게 된다.


해결 방법

계속 입력으로 고통받을 수는 없다.

1. whitespace

오늘도 어김없이 등장하는 레퍼런스 페이지.
저학때는 몰랐는데 어지간한건 다 레퍼런스에서 해결가능하다.

scanf 사용 시 whitespace(== 스페이스바)를 넣어주면 읽혀들여온 내용 중 공백은 모두 무시해준다는 얘기다. 공백, \n, \t 등등 모두 처리해준다.

scanf(" %c", &_char);

공백 하나만 넣어주면 띄어쓰기를 몇번을 하던, 탭을 누르던 알아서 처리해준다!


2. 입력 버퍼 비우기

standard input stream = stdin을 비우면 된다. 크게 두가지 방법이 있다.

2.1. fflush

첫 번째 방법은 후처리 방식이라면 아예 입력 버퍼를 비우고 다음 입력을 받아서 해결할 수도 있다.

scanf("%c", &_char);
fflush(stdin);

💀 주의 💀
표준 fflush() 함수는 출력버퍼를 비운다. 따라서 gcc 환경에서는 안된다고 알고 있다.

2.2. rewind

2.1.과 미묘하게 다른듯 비슷한 방법으로는 입력 버퍼의 포인터를 변경하는 방법이다. 공백까지 입력을 받았는데 입력 버퍼의 포인터를 맨 앞으로 이동시킨다. 버퍼를 이동하는 것만으로 비우는 효과인 셈이다.

scanf("%c", &_char);
rewind(stdin);

참고 페이지

cplusplus.com

그 외


💬 주저리

평소에 마주해도 급하게 해결하고 넘어가는 자잘한 문제인 것 같다. 여유로울 때 원인도 찾아보고 레퍼런스 페이지도 뒤적뒤적해보는 재미가 있다.

거의 한달만에 벨로그 글을 작성했다. 일렉트론은 했는데 글로 정리를 못하고 있다... 조만간 꼭 올려야지..

profile
개발자가 되고 싶은 맽튜

0개의 댓글