[C/C++]입력 예외 처리(Handling input exceptions)
2022. 4. 7. 23:54ㆍProgramming language/C, C++
- 목차
이 글은 이전에 운영하던 깃 블로그에서 옮겨온 글입니다.
서론
프로그래밍을 하다 보면, 사용자 입력을 받아야 할 때가 생긴다. C와 C++에서는 표준 입력 함수인 scanf() 함수와 C++의 std::cin istream 객체가 있겠다. 이러한 것들을 이용하여 사용자 입력을 받을 때 '잘못된 데이터'를 받는다면?
현상
예를 들어 보겠습니다.
int num = -1;
printf("정수 입력");
scanf("%d", &num);
위와 같은 코드에서 만약 문자(%c format) 같은 것을 입력한다면?
결론만 말하자면 유감스러운 결과를 보게 될 것입니다. 루프 안에 저 코드가 있다면 끔찍한 무한루프를 겪게 될 것이며, num의 값은 -1로 고정될 것입니다.
scanf() 와 std::cin 모두 다음과 같은 구조로 입력받습니다.
- 입력 버퍼에서 값을 읽어, 자신의 입력 포맷과 맞는지 검사
- 포맷과 맞는다면, 버퍼에서 값을 꺼내 입력
- 포맷과 맞지 않는다면, 버퍼에 값을 그대로 남겨 놓음
- 이 작업은 버퍼가 비어있을 때까지 반복
-> 루프에서 문제가 생기는 건 이 과정이 반복되기 때문
즉, 버퍼를 비우지 않으면 다음 입력을 제대로 받지 못하게 된다는 것입니다.
만약 값을 잘못 입력받는 예외 처리를 하고 싶다면, 입력 버퍼를 지워 주도록 합니다.
해결책
scanf() 해결책
int num = -1;
printf("정수 입력");
rewind(stdin); // 입력버퍼 비우기
scanf("%d", &num);
std::cin 해결책
int num = -1;
// 입력에 실패하였는가?
if (std::cin.fail()) {
// 실패했다면
std::cin.ignore(INT_MAX, '\n'); // 입력하여 문자로 인식한'\n'도 무시
std::cin.clear(); // 입력 가능상태로 되돌리기
}
rewind(stdin); // 입력버퍼 비우기
std::cout << "정수를 입력하세요\n";
std::cin >> num;
std::cin은 클래스 객체입니다. 함수와는 달리 내부적으로 변경된 값이 있어 해당 값을 초기화해주는 과정이 필요하기에 rewind(stdin); 만으로는 해결이 안 될 것입니다. 참고로 fflush(stdin); 표준이 아니라 더는 지원이 안 된다고 합니다.
여담 : 꽤 오래된 이야기지만, Visual studio 2010 이상부터는 scanf_s();를 사용하도록 권장합니다. 해결책은 동일.
반응형
LIST
'Programming language > C, C++' 카테고리의 다른 글
[C/C++] 캐스팅연산자 (0) | 2022.04.08 |
---|---|
[C/C++]STL 컨테이너 - std::map/std::set 그리고 std::deque (0) | 2022.04.08 |
[C/C++]STL 컨테이너 - std::vector 와 std::list (0) | 2022.04.08 |
[C/C++]L-Value와 R-Value (0) | 2022.04.08 |
[C/C++]이동의미론(Move Semantics) (0) | 2022.04.08 |