본문 바로가기

programming/문제 해결

[C언어, C++] scanf() 문자 입력 문제 - 입력 버퍼

반응형

1. 개요

 

이 카테고리는 내가 겪은 문제들, 그리고 이 문제들을 해결하는 과정을 정리하고자 만든 카테고리이다. 사실 엄청난 문제들도 아니다 ㅎㅎ 사소한 문제가 대부분이지만, 때론 사소한 문제들이 극심함 스트레스를 만들기도 하기 때문에 많은 사람들의 스트레스 해소에 조금이라도 도움이 되었으면 좋겠다.

 

2. 문제

 

 만약 내가 두개의 문자를 입력받고 그 프로그램을 출력하는 코드를 작성했다고 가정해보자 아마 다음과 같은 코드가 만들어 질 것이다.

 

*#include <stdio.h>

int main(void) {

	char value1, value2;


	scanf("%c", &value1);
	scanf("%c", &value2);

	printf("첫 번째 문자%c\n", value1);
	printf("두 번째 문자%c", value2);

	return 0;
}

 

 자 보기엔 아무 문제가 없다. 차례대로 두개의 문자를 입력받고 출력만하면 되기 때문이다. 하지만 정작 위의 프로그램을 실행해본다면 문제가 별견된다 다음은 실행결과이다.


실행 화면


 두 번째 문자를 입력받지 않고 바로 처음으로 받은 문자를 출력한 것이다. 자세히 보면 알겠지만 C언어의 printf()함수는 파이썬의 print() 함수와는 다르게 함수가 종료되었다고 해서 줄바꿈 문자(\n)을 출력하지 않는다. 하지만 '두 번재 문자' 라는 문자열이 출력되고 줄바꿈이 일어났다. 

 

 실제로 이 문제는 내 동기들도 많이 물어볼만큼 자주 발생하는 문제이다. 차라리 문법 오류였다면 빨간줄이라도 보고 오류 메세지를 해석하거나 구글링을 했겠지만, 이런 오류가 아닌 모르는 부분에서 나오는 문제는 참 힘을 빠지게 한다. 자, 그럼 왜 이런 결과가 나타나는지 한번 살펴보자.

 

3. 문제 해결 과정

 

- 버퍼

 

 우리가 cmd창에 값을 입력할 때 운영체제는 이 값을 바로 프로그램으로 전달하지 않는다. 어떠한 공간에 이 값을 따로 저장하고, 그 값을 다시 프로그램으로 돌려주게된다. '왜 이런 비효율적인 방법을 사용하지?' 라는 궁금증이 생기는 것은 당연하다. 그냥 값을 바로 프로그램으로 주는 것이 효율적이지 않을까? 

 

 놀랍게도 운영체제가 이러한 방식을 사용하는 이유는 효율성 때문이다. 만약 우리가 사과 5개를 우리집에서 할머니 댁까지 옮긴다고 생각해보자. 사과를 하나씩 가져다 드리면 5번을 왔다갔다 해야한다. 할머니 댁으로 가는 거리를 1km라고 가정했을 때 사과 5개를 옮기려면 10km를 움직여야한다. 혹시라도 할머니가 사과를 너무 좋아하셔서 30개를 가져다 드려야한다면? 얼마나 많은 시간과 에너지를 낭비할까? 대신 큰 수레에 30개를 다 담아서 한번에 가져다 다른다면 우리는 단 한번만 할머니 댁을 방문하면 된다. 그리고 이것이 운영체제가 위와같이 비효율적일 것 같은 방식을 사용하는 이유이다.

 

*그래서 버퍼가 뭔데요?*

 위에서 말한 값을 프로그램에 전달하지 않고 먼저 보관하는 공간, 이 공간의 이름이 바로 버퍼이다. 그릐고 이 버퍼의 값을 담아 한번에 프로그램으로 전송해주는 방식을 버퍼링이라고 한다. 이런 버퍼는 표준 입출력 함수들을 통해 값을 입력받을 때 사용하게 되는데 위에서 사용한 scanf(), printf()함수가 전부 표준 입출력함수이기 때문에 버퍼를 사용하게 된다.

 

- 문제 원인

 

 그럼 한번 저 프로그램을 실행할 때, 메모리가 어떻게 변하는지 살펴보자 우리가 첫 입력을 'a'라고 한다면 cmd창에 'a'를 입력하고 엔터를 칠 것이다. 그럼 다음과 같은 상황이 발생된다.



 이렇게 버퍼에 'a'와 '\n' 이 입력된다. 그렇게 되면 'a'가 value1변수에 저장되는데 나머지 문자는 남아있어, 다음과 같은 상황이 된다.



 남아있는 문자는 사라지는 것이 아니라 다음 그림 처럼 다음 입력값으로 들어가게 된다. 결국 value2가 저장되는 다음 그림과 같은 상황이 발생하는 것이다. 



- 해결방법

 

 다양한 해결방법이 있다. 실제로 저 버퍼를 비우는 방법도 존재한다. 그러나 그 방법은 컴파일러나 visual studio의 버전에 따라 많이 다른 것으로 알고있다. 다음은 내가 가장 선호하는 두가지 방법이다.

 

방법1 - getchar() 함수의 사용

 

 scanf()함수 다음에 getchar()함수를 넣어주면 줄바꿈문자를 먹어 치우기 때문에 정상적인 실행이 가능하다. 다음은 예시 코드이다.

 

#include <stdio.h>

int main(void) {

	char value1, value2;


	scanf("%c", &value1);
	getchar();
	scanf("%c", &value2);

	printf("첫 번째 문자%c\n", value1);
	printf("두 번째 문자%c\n", value2);

	return 0;
}

 

방법2 - 다른 입력 변수 생성

 

 새로운 변수를 선언하여 줄바꿈 문자를 그 변수에 넣어주는 방법이 있다. 다음은 이 방법을 사용하여 문제를 해결한 코드이다.

 

#include <stdio.h>

int main(void) {

	char value1, value2, trash;


	scanf("%c%c", &value1,&trash);
	scanf("%c", &value2);

	printf("첫 번째 문자%c\n", value1);
	printf("두 번째 문자%c\n", value2);

	return 0;
}

 

4. 결어

 

 이런 사소한 문제들을 해결해서 올리는 것이 분명 나한텓 도움이 되는 것을 안다. 이렇게 문제를 해결하는 글을 더욱 많이 올렸으면 좋겠다.

반응형