본문 바로가기

C언어프로그래밍

Scanf 미스테리, 그것이 알고싶다.

반응형

함수 scanf ( ) 사용법 제대로 알기


콘솔창을 통해 키보드 입력을 받을 때 유용하게 사용할 수 있는 함수가 scanf이다. 

그런데, scanf의 동작이 미스테리할 때가 있다.

예상치도 않게 줄바꿈이 생기는 현상이 발생할 수 있는데, 여기서는 왜 그런 일이 발생하는지 설명하고, 

고칠 수 있는 방법을 제시한다.


우선, scanf( )가 정상적으로 동작하는 경우를 살펴보자.

간단한 예제 프로그램을 하나 작성해 보자. 

콘솔창에서 숫자를 입력받아서 그 값을 출력하는 동작을 반복하고,

입력값이 -999이면 종료하는 프로그램이다.

소스코드는 아래와 같다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>

int main(void)
{
	int data;

	while (1)
	{
		printf("Enter number: ");
		scanf("%d", &data);

		printf("Data is %d\n", data);
		if (data == -999)
		{
			printf("Program ended\n");
			break;
		}
	}

	return 0;
}


실행해 보면, 아래 그림과 같이 예상대로 잘 동작하는 것을 알 수 있다.


미스테리 속으로 

이번에는 문자값을 입력받아 출력을 반복하는 프로그램을 작성해 보자.

다만 문자 'z'가 입력되면 종료된다.

소스코드는 위의 프로그램에서 int 대신 char, 형식지정자는 %d 대신 %c 로 바꾸는 정도로 수정하면 된다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>

int main(void)
{
	char data;

	while (1)
	{
		printf("Enter char: ");
		scanf("%c", &data);

		printf("Data is %c\n", data);
		if (data == 'z')
		{
			printf("Program ended\n");
			break;
		}
	}
}

하지만 실행결과는 아래와 같이 엉망진창이다.

첫 글자 'a'는 정상적으로 출력되었다. 하지만 두 번째 문자 'b'를 입력받기 전에

"Enter char: Data is "와 그리고 공백줄이 출력되면서 꼬이기 시작한다. 

왜 이런 문제가 발생했을까? 숫자를 입력받을 때는 괜찮았는데.. 


미스테리의 원인을 찾아서


위와 같은 문제가 발생한 원인을 추적해보자.

프로그램이 막 시작된 순간을 생각해보자.

사용자는  문자 'a'를 입력하고 엔터키를 눌렀을 것이다.

콘솔창은 scanf에게 그것들을 넘기기 위해 

우선 입력버퍼(input buffer)라는 특수공간에 아래 그림과 같이 문자 'a'와 엔터키값 '\n'을 저장한다.


그러면 scanf는 line 10을 수행하여

		scanf("%c", &data);

입력버퍼에서 한 글자만 읽어서 변수 data에 저장한다.

이렇게 되면, 아래 그림과 같이 scanf는 입력버퍼에서 문자 'a'만 가져가고, '\n'는 남게된다.


가져간 문자 'a'는 출력되고,

다시 while문의 처음으로 와서, line 9와 10을 실행하게 되는데,

		printf("Enter char: ");
		scanf("%c", &data);

이 때, 입력버퍼에 이미 '\n'이 있으므로

사용자의 입력을 기다릴 필요없이 변수 data에는 '\n'이 입력된다.

그래서 "Enter Data : Data is + \n"이 출력되는 것이고, 아래 그림의 빨간 색으로 표시한 부분이다.


그렇다면 첫 번째 프로그램에서는 왜 이런 일이 발생하지 않은 것일까?

scanf("%d")와 scanf("%c")의 차이다.

'\n'는 문자이므로, 첫 번째 프로그램에서는 %d에 해당되지 않으므로

입력대상에서 제외된 것이고, 두 번째 프로그램에서는 입력으로 분류된 것이다.


미스테리를 해결해 보자


문제 해결은 너무나도 간단하다.

변경전



변경후

차이점은 line 10의 scanf에서 "%c" 대신에

공백을 앞에 하나 더 추가하여 " %c"로 하는 것이다.


왜 이것이 해결책이 되는가를 설명해 보자.

scanf는 공백, 줄바꿈, 탭문자 등을 모두 같은 것으로 인식한다는 점을 이용하자.

즉, 입력버퍼에 남아있던 '\n'는 "  %c"에서 앞의 공백으로

인식되기 때문에 data에 입력되지 않고, 실제로 입력한 문자가 data로 들어가게 된다.


아직 의문이 하나 더 남아있다.

처음 프로그램을 시작한 직후에는 '\n'이 입력버퍼에 없는데

어떻게 동작하는 것일까?

scanf는 공백문자가 입력되지 않으면 그냥 pass하고 지나간다는 성질때문이다.

그래서 최초에 "a\n"이 입력되었을 때, 'a'앞에 공백문자가

없어도 data에 'a'를 읽어 들이는데 아무 문제가 없었던 것이다.


수정하여 실행한 결과 예상대로 잘 동작하는 것을 알 수 있다.







반응형