코딩하는 공무원

scanf(), getchar() 함수로 문자 하나를 읽어 올 때 주의할 점 본문

프로그래밍

scanf(), getchar() 함수로 문자 하나를 읽어 올 때 주의할 점

코딩펀 2010. 5. 4. 23:55

scanf() 함수나 getchar() 함수를 이용하여 문자 하나를 입력 받을 때 주의할 사항이 있습니다. 만약, 숫자를 입력 받기 위해 scanf() 함수에서 %d를 사용한다면, 신경쓰지 않으셔도 됩니다.


#include <stdio.h>

int main()
{
    char ch;
    printf("첫번째 문자 입력 : ");
    scanf("%c",&ch);
    printf("첫번째 문자는 %c\n",ch);
    printf("두번째 문자 입력 : ");
    scanf("%c",&ch);
    printf("두번째 문자는 %c\n",ch);
    return 0;
}

 

다음과 같은 소스 코드를 실행한다면, 어떻게 출력될까요?

아마 프로그램은 다음 그림처럼 진행될 것을 예상하고 코딩 했을 겁니다.

 

 

 

그러나 아쉽게도 예상과는 달리 아래의 그림처럼 실행됩니다.

 

 

즉, 두번째 문자는 입력할 기회도 없이 그냥 끝나버리게 되는 것입니다. 도대체 왜 이런 일이 벌어질까요?

 

그 해답은 “키보드 버퍼”에 있습니다. scanf() 함수나 getchar() 함수는 데이터를 입력 받을 때 버퍼를 이용합니다. 이 함수가 실행되면, 제일 먼저 버퍼를 조사합니다. 버퍼에 가져올 값이 없으면 사용자에게 데이터를 입력 받기 위해 모니터 화면에 커서를 깜빡 거리게 하지요.. 사용자가 키보드로 데이터를 입력한 후 Enter를 치면, 그때 입력한 데이터와 Enter가 한꺼번에 키보드 버퍼에 들어가게 됩니다. 위의 예에서 사용자가 ‘a’와 Enter를 입력하면 a와 Enter가 버퍼에 들어가는 것입니다. 그러면 첫번째 scanf() 함수가 버퍼에 있는 ‘a’를 가져옵니다. 아직 버퍼에는 Enter가 찌꺼기 처럼 남아 있습니다. Enter는 아스키 코드 값으로 10입니다. 즉, 문자로 인식된다는 것입니다. 이 찌꺼기를 두번째 scanf()가 덥석 받아들이고 마는 것이지요…

 

그렇다면, 이것을 해결할 수 있는 방법은 무엇일까요? 결국 버퍼에 찌꺼기 처럼 남아 있는 Enter를 없애버리는 것입니다. 다음은 2가지 해결 방안입니다. 빨간색으로 친 부분을 유념해서 살펴보세요.

 

 

해결 방안 1

 

#include <stdio.h>

int main()
{
    char ch;
    printf("첫번째 문자 입력 : ");
    scanf("%c",&ch);

    fflush(stdin);  // 표준 입력(키보드) 버퍼를 비워 버리는 함수
    printf("첫번째 문자는 %c\n",ch);
    printf("두번째 문자 입력 : ");
    scanf("%c",&ch);
    printf("두번째 문자는 %c\n",ch);
    return 0;
}



해결 방안 2

 

#include <stdio.h>

int main()
{
    char ch;
    printf("첫번째 문자 입력 : ");
    scanf("%c",&ch);

    printf("첫번째 문자는 %c\n",ch);

    scanf("%c",&ch); // 버퍼에 찌꺼기 처럼 남아 있는 Enter를 소비시켜 버리기 위한 scanf() 함수
    printf("두번째 문자 입력 : ");
    scanf("%c",&ch);
    printf("두번째 문자는 %c\n",ch);
    return 0;
}

 


 

fscanf() 함수의 경우는 비슷한 증상이 발생합니다만, 그 원인은 다릅니다.

 

input.txt의 내용이 다음과 같습니다.

 

a

b

EOF

 

이때, 아래의 코드를 실행하면 어떻게 될까요?

 

#include <stdio.h>

int main()
{
    FILE *fp = fopen("input.txt","r");

    char ch;

    fscanf(fp,"%c",&ch);
    printf("첫번째 문자는 %c\n",ch);

    fscanf(fp,"%c",&ch);
    printf("두번째 문자는 %c\n",ch);
    return 0;
}

 

 

 

 

여기서 원인은 “키보드 버퍼”가 아닙니다. scanf() 함수나 fscanf() 함수는 공백, 탭, 개행 문자를 데이터의 입력 단위로 인식하는데, 여기서는 a만 입력 받고, 파일 포인터가 줄 마지막의 개행 문자를 가리키고 있으므로, 당연히 두번째 fscanf() 함수에서 개행 문자를 읽어 버리기 때문입니다. (이 역시 두번째 scanf() 함수에서 수치값을 입력 받는 경우라면 문제가 되질 않습니다.)

 

 

해결 방안 1

 

 

#include <stdio.h>

int main()
{
    FILE *fp = fopen("input.txt","r");

    char ch;
    fscanf(fp,"%c",&ch);
    printf("첫번째 문자는 %c\n",ch);
    fscanf(fp,"%c",&ch); // 파일 포인터가 가리키고 있는 개행 문자를 읽어서 파일 포인터를 그 다음 문자를 가리키도록 함

    fscanf(fp,"%c",&ch);

    printf("두번째 문자는 %c\n",ch);

    return 0;
}

 

 

해결 방안 2

 

 

#include <stdio.h>

int main()
{
    FILE *fp = fopen("input.txt","r");

    char ch;
    fscanf(fp,"%c",&ch);
    printf("첫번째 문자는 %c\n",ch);
    fseek(fp,2,SEEK_CUR ); // 파일 포인터를 직접 오프셋 만큼 이동시킴

    fscanf(fp,"%c",&ch);
    printf("두번째 문자는 %c\n",ch);
    return 0;
}

'프로그래밍' 카테고리의 다른 글

무료 C, C++ 컴파일러 Code::Blocks  (0) 2010.05.07
Code::Blocks 설치하기  (0) 2010.05.07
문자열 입력 함수 fscanf(), fgets()  (7) 2010.04.22
wxDev-C++ 공개 컴파일러  (0) 2010.03.31
EditPlus를 능가하는 AcroEdit  (0) 2009.12.04
Comments