C 언어 - 버퍼와 scanf 함수 (다양한 에러의 원인과 해결법)

컴퓨터/C

728x90
반응형

scanf의 맹점 - 입력 버퍼와의 관계

C언어를 이용하여 다양한 프로그래밍을 하다 보면 아래와 같은 경우를 자주 만나게 됩니다.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main() {
	int numinput;
	char charinput;
	scanf("%d", &numinput);
	printf("%d\n", numinput);
	scanf("%c" ,&charinput);
	printf("%c", charinput);
	//예상 결과는 ??
	return 0;
}

소스코드를 읽어와는 다른 결과가 나오면서 종료가 됩니다.

프로그래머는 2번의 입력과 2번의 출력을 만들려고 했지만 애석하게도 프로그램에서는 원하는 데로 동작을 하지 않습니다.

 

그렇다면 그 원인이 무엇일까요?

 

scanf함수는 버퍼에 담겨 있는 내용을 가지고 온다.

버퍼를 이용하여 우리는 장치와 장치 간의 속도 차이를 극복할 수 있게 되었습니다.  scanf 또한 입력되는 값을 하나씩 받는 것이 아니라, 버퍼에 저장된 뭉텅이 데이터를 받아옵니다. 그렇다면 위와 같은 소스코드에서 입력 버퍼는 어떤 식으로 데이터를 가지고 있고, scanf는 활용을 하는지 알아보도록 합시다.

 

  • scanf에서 입력 버퍼에 저장되어있는 하나의 형식 지정자 값을 가지고 온다. 
	scanf("%d", &numinput);

사용자가 100이라는 int값을

입력하고 엔터를 누르게 되면 입력 버퍼에는 아래와 같이 데이터가 남게 됩니다.

scanf에서 "% d"라는 형식 지정자로 숫자를 하나 버퍼에서 불러옵니다. 

이때 우리는 scanf 함수를 이용하기 위해 엔터를 눌렀습니다. 그리고 이 엔터 또한 키보드 입력 버퍼 공간에는 줄 넘김을 표현하기 위한 개행 문자인 '\n'이 입력되어 있습니다.

 

  • 2번째 scanf가 실행되면 어떻게 될까요?
	scanf("%c" ,&charinput);

이처럼 키보드 입력 버퍼에 개행 문자가 담겨 있기 때문에 문자 하나를 입력하는 % c 형식 지정자의 경우 개행 문자를 가지고 옵니다. 프로그래머가 원하지 않는 경우가 생기는 것입니다. 

 

해결 방법

이제 위와 같은 소스코드에서 원인을 알 수 있게 되었습니다.

  • scanf함수는 입력 버퍼에서 값을 가지고 온다.
  • % c의 경우 입력 버퍼에서 문자를 가지고 온다. 따라서 엔터등의 입력으로 입력버퍼에 개행문자가 담겨 있다면 문제가 생길 수 있다.

해결 방법을 생각해보자면 가장 근본적인 방법은 아래와 같습니다.

  • 입력버퍼에 담겨져 있는 데이터를 이해하고 컨트롤할 수 있으면 된다.

간단하게 몇 가지 방법에 대해 설명해 드리도록 하겠습니다.

 

버퍼 값 초기화 하기 - fflush 함수

fflush 함수는 어떤 스트림의 버퍼를 비우겠다는 의미의 함수입니다.

따라서 표준 입력 스트림 버퍼를 초기화하고 싶으면 아래와 같이 사용하면 됩니다.

fflush(stdin);

하지만 이 방식은 비표준 방식이며 작동하지 않는 환경이 더 많이 있습니다. 따라서 사용하지 않는 것이 바람직합니다.

 

버퍼에서 받아오는 위치를 초기화 하기 - rewind 함수

입력 버퍼의 위치를 되감아 처음의 위치부터 받게 하는 함수입니다. fflush와 비슷한 개념입니다.

rewind(stdin);

이 또한 다른 환경에서 올바르게 동작하지 않을 수 있어 사용하지 않는 것이 바람직합니다.

 

입력과 동시에 저장된 개행 문자를 사용해버리기 - getchar 함수

위와 같은 소스코드에서 문제는 입력 후에 개행 문자가 입력 버퍼에 남아있는 것 입니다. 

그렇다면 getchar함수를 이용하여 하나의 문자를 바로 사용해버린다면 문제 해결이 가능합니다. 

scanf에서 입력을 마치면서 입력버퍼에 들어간 개행 문자를 getchar함수를 이용해 사용해 버리는 것입니다.


	scanf("%d", &numinput);
	printf("%d\n", numinput);
	getchar();
	scanf("%c" ,&charinput);
	printf("%c", charinput);

 

scanf의 기능 이용하기 공백과 개행 문자를 무시하기 

scanf에서 문자를 받을 때 아래와 같이 사용하면 개행 문자와 공백을 무시하고 문자를 받을 수 있습니다.

 //scanf("%c",&charinput);
scanf(" %c",&charinput); //위와 차이점은 스페이스 하나뿐

위와 같은 식으로 scanf함수를 이용하면 입력 버퍼 중 공백과 개행 문자를 무시하고 처음으로 만나는 문자의 값을 취하겠다는 뜻입니다.

 

 

728x90
반응형

'컴퓨터 > C' 카테고리의 다른 글

C 언어 - scan 무한 반복 에러  (0) 2021.12.01
C 언어 - 예외처리  (0) 2021.11.30
C 언어 - 버퍼(Buffer)의 개념과 이해  (0) 2021.11.24
C 언어 - time.h  (0) 2021.10.02
C 언어 - NULL  (0) 2021.09.30

Commnet

G91개발일지

Gon91(지구일)

91년생 공학엔지니어의 개발일지

TODAY :

YESTER DAY :

TOTAL :