Quick Reference
scanf는 성공한 변환 개수를 반환하고, 읽지 않은 문자를 stdin에 남깁니다. 숫자 뒤 문자를 읽을 때는 format 앞 공백으로 whitespace를 건너뛰고, 실패한 줄은 getchar로 비웁니다.
if (scanf("%d", &n) != 1) {
/* 실패 처리 */
}
if (scanf(" %c", &ch) != 1) {
/* 앞 공백이 남은 개행을 건너뛴다. */
}
char word[32];
if (scanf("%31s", word) != 1) {
/* buffer보다 하나 작은 field width */
}변환이 실패하면 실패 토큰은 stdin에 남습니다. 공백·범위·남는 문자까지 검증해야 하는 입력은 fgets로 줄을 받은 뒤 strtol처럼 해석 함수를 쓰는 편이 낫습니다.
문법
사용자가 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 */
}문자열 변환 %s와 %[...]에는 destination capacity보다 하나 작은 width가 필요합니다. 형식 문자열 속 공백은 "공백 하나"가 아니라 다음 non-whitespace까지 건너뛰라는 뜻이고, literal 문자는 입력에 그대로 있어야 합니다. 부분 변환 뒤 남은 문자를 허용할지까지 입력 문법으로 정합니다.
선택 기준
형식이 조금만 복잡해져도 줄 단위로 읽고 파싱하는 쪽이 더 안정적입니다.
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;
}위 sscanf는 1 2junk에서 두 숫자만 읽고 성공으로 볼 수 있습니다. 줄 전체가 숫자 두 개여야 한다면 추가 문자까지 검사하거나 strtol의 end pointer로 끝까지 소비했는지 확인합니다. 큰 정수를 더 작은 목적 타입으로 옮길 때도 범위 검사는 별도로 합니다.
이 패턴은 입력 줄 경계가 명확하고, 실패했을 때 원본 입력을 다시 볼 수 있다는 장점이 있습니다.
빠른 점검
%d는 숫자만 읽고 개행을 남길 수 있습니다.%c앞 공백은 남은 whitespace를 건너뛰는 데 자주 필요합니다.scanf는 항상 반환값으로 성공 개수를 확인해야 합니다.- 실패 뒤에는 버퍼를 정리해야 다음 입력이 정상화됩니다.
- 복합 입력은
fgets + sscanf가 더 안정적인 경우가 많습니다. fflush(stdin)은 표준적인 입력 정리 해법이 아닙니다.
주의할 점
fflush(stdin)은 표준 C에서 입력 스트림 정리에 쓰는 함수가 아닙니다. 어떤 환경에서는 동작해 보여도 이식성이 없습니다. 버퍼 정리는 getchar 루프나 fgets 기반 입력으로 해결하는 편이 맞습니다.
참고 링크
2 sources