프로그래밍/C

C언어 입력함수 scanf와 입력 버퍼

swedu 2023. 1. 2. 17:45
728x90
반응형

2023.1.2. 최초 작성

 

 

 

C언어의 표준입력 함수로 서식에 맞춰 데이터를 입력받는다.

#include <stdio.h>
void main() {
	int a;
	printf("숫자를 입력하세요. ");
	scanf("%d", &a);
	printf("a : %d\n", a);
}

 

위 코드로 실행하면 아래와 같은 오류가 발생한다.

[그림1] scanf 오류

 

scanf 함수가 보안에 취약하여 사용하지 말라는 경고이다. scanf 함수는 키보드로 입력받을 때 데이터 길이를 체크 하지 않아 메모리에 선언된 변수의 크기를 넘어 다른 영역을 덮어써지는 문제가 있다. 오버플로우 취약점이라고 한다.

 

보안대책으로는 오버플로우 취약점을 보완한 scanf_s 함수를 사용하는 것을 권고한다.

#include <stdio.h>
void main() {
	int a;
	printf("숫자를 입력하세요. ");
	scanf_s("%d", &a);
	printf("a : %d\n", a);
}

 

위 코드는 scanf_s 함수를 사용한 예제이다. 정수를 입력받을 때는 함수 이름만 바뀌었고 차이 없다. 하지만 문자열을 입력받을 때는 문자열의 길이를 같이 입력해야 한다.

 

지금은 문자열을 다루지 않으므로 넘어간다.

키보드에서 입력받은 정수를 a변수에 넣는 예제이다. a앞에 사용한 &는 주소 연산자이다.

입력받을 때는 변수의 주소를 알아야 한다.

 

scanf_s 함수를 쓰지않고 scanf 함수를 쓸 때 에러가 나오지 않으려면 맨 위에 한 줄을 추가한다.

 
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
void main() {
	int a;
	printf("숫자를 입력하세요. ");
	scanf_s("%d", &a);
	printf("a : %d\n", a);
}

 

# 으로 시작하는 명령어는 컴파일 이전 전처리기에서 담당하는 명령어이다.

전처리기에게 보안 경고를 띄우지 말라고 알려주는 것이다.

 

맨 위에 한 줄 쓰는 것이 번거로우면 Visual Studio의 설정에서 보안검사를 해제하는 방법도 있다.

 

솔루션탐색기의 프로젝트 이름에 마우스 오른쪽 버튼을 클릭 --> 속성을 클릭한다.

[그림2] 프로젝트 속성

 

[그림3] SDL 검사 해제

 

구성 속성 --> C/C++ 메뉴에 SDL 검사를 아니요로 바꿔준다.

 

scanf 함수를 문자를 입력받을 때 조심 해야 하는 것이 있는데 입력 버퍼에 남아 있는 엔터이다.

#include <stdio.h>
void main() {
	int a;
	int b;
	char c;
	printf("숫자를 2개 입력하세요.");
	scanf("%d %d", &a, &b);
	printf("a : %c, a : %c, b : %lf\n", a, (char)a, (double)b);
	printf("문자를 1개 입력하세요.");
	//fflush(stdin); // 현재는 안 먹힘
	//getchar();  // 입력버퍼를 비우기 위해 사용
	scanf("%c", &c);
	printf("c : %c, c : %d, c : %f\n", c, (int)c, (float)c);
}
 

위 코드는 처음에 숫자 두 개를 입력받아 ab에 넣고 문자 하나를 입력받아 c에 넣는 프로그램이다. 그러나 실행해보면 문자는 입력받지 않고 그냥 종료된다.

 

그 이유는 키보드에 입력된 정보들이 입력 버퍼에 머물다 변수에 저장되는데 숫자를 입력 후 엔터가 남아 있다가 문자를 받아들이는 %c에 의해 c변수에 저장되기 때문이다.

 
 
[그림4] 입력버퍼(키보드버퍼)

 

 

이 문제를 해결하기 위해서는 입력 버퍼에 남아 있는 \n을 문자를 입력받기 전에 비워야한다.

 

예전에는 fflush(stdin)으로 입력 버퍼를 비웠으나 c언어 표준에서 지원하는 것이 아니므로 Visual Studio에서 요즘에는 지원하지 않는다. 과거 버전의 Visual Studio에서는 지원한다.

 

fflush(stdin) 방식은 안 쓰는 것이 좋다. 문자 하나를 입력받는 getchar() 함수를 사용하여 입력 버퍼의 \n을 읽어서 버리는 방법으로 이 문제를 해결할 수 있다.

 

 

printf("a : %c, a : %c, b : %lf\n", a, (char)a, (double)b);

printf("c : %c, c : %d, c : %f\n", c, (int)c, (float)c);

 

위 두 줄의 코드에서 변수명 앞에 괄호로 자료형을 표시하면 타입 변환이 가능하다.

 

getchar() 함수 앞에 주석을 풀고 실행하면 아래와 같이 실행된다.

 

[그림5] scanf 정상 실행 결과

 

728x90
반응형

 

728x90
반응형