scanf 문제는 문법보다 반환값 검사와 입력 버퍼 상태를 같이 안 보는 데서 시작합니다.
scanf("%d", &n)다음scanf("%c", &ch)가 왜 바로 개행을 읽는지 다시 보고 싶다- 잘못된 입력 뒤 루프가 왜 계속 실패하는지 정리하고 싶다
fflush(stdin)대신 무엇을 써야 하는지 확인하고 싶다
숏컷 코드
if (scanf("%d", &n) != 1) {
/* 실패 처리 */
}
scanf(" %c", &ch);문법
사용자가 42↵를 입력하면 버퍼에는 4, 2, \n이 들어갑니다.
int n;
char ch;
scanf("%d", &n);
scanf("%c", &ch); // 남은 '\n'을 읽기 쉽다%d는 숫자만 읽고 멈추기 때문에 개행은 버퍼에 남습니다. 그래서 다음 %c가 그 개행을 읽어 버립니다. 문자 하나를 읽을 때 형식 문자열 앞 공백을 두는 이유가 여기 있습니다.
if (scanf(" %c", &ch) != 1) {
return 1;
}확인 포인트
scanf는 성공한 항목 개수를 반환하므로, 입력 검증에서는 거의 항상 반환값을 같이 봐야 합니다.
int a, b;
int ret = scanf("%d %d", &a, &b);
if (ret != 2) {
fprintf(stderr, "정수 두 개가 필요합니다\n");
}실패 뒤에는 잘못된 입력 줄을 버리고 다시 읽을 준비를 해야 합니다.
int ch_clear;
while ((ch_clear = getchar()) != '\n' && ch_clear != EOF) {
/* discard */
}선택 기준
형식이 조금만 복잡해져도 줄 단위로 읽고 파싱하는 쪽이 더 안정적입니다.
char line[128];
int a, b;
if (fgets(line, sizeof(line), stdin) == NULL) {
return 1;
}
if (sscanf(line, "%d %d", &a, &b) != 2) {
fprintf(stderr, "정수 두 개가 필요합니다\n");
return 1;
}이 패턴은 입력 줄 경계가 명확하고, 실패했을 때 원본 입력을 다시 볼 수 있다는 장점이 있습니다.
체크포인트
%d는 숫자만 읽고 개행을 남길 수 있습니다.%c앞 공백은 남은 whitespace를 건너뛰는 데 자주 필요합니다.scanf는 항상 반환값으로 성공 개수를 확인해야 합니다.- 실패 뒤에는 버퍼를 정리해야 다음 입력이 정상화됩니다.
- 복합 입력은
fgets + sscanf가 더 안정적인 경우가 많습니다. fflush(stdin)은 표준적인 입력 정리 해법이 아닙니다.
주의할 점
fflush(stdin)은 표준 C에서 입력 스트림 정리에 쓰는 함수가 아닙니다. 어떤 환경에서는 동작해 보여도 이식성이 없습니다. 버퍼 정리는 getchar 루프나 fgets 기반 입력으로 해결하는 편이 맞습니다.
참고 링크
1 sources