scanf 건너뜀
글쓴이: 한동수@Facebook / 작성시간: 수, 2017/06/07 - 9:17오후
#include
int main(){
char c;
int a,b;
printf("첫 번째 정수를 입력하세요: ");
scanf("%lf",&a);
printf("두 번째 정수를 입력하세요: ");
scanf("%lf",&b);
printf("수행할 연산을 입력하세요: ");
scanf("%c",&c); //자꾸 이부분을 건너뛰어요 ㅠ
switch(c){
case '+':
printf("%.0lf+%.0lf = %.0lf\n", a, b, a + b);
break;
case '-':
printf("%.0lf-%.0lf = %.0lf\n", a, b, a - b);
break;
case '*':
printf("%.0lf*%.0lf = %.0lf\n", a, b, a * b);
break;
case '/':
printf("%.0lf/%.0lf = %.0lf\n", a, b, a / b);
break;
}
if(b == 0){
printf("오류\n");
return 0;
}
if (a > 30000 || b > 30000){
return 0;
}
}
Forums:
버퍼 비워주셔야합니다.
printf("첫 번째 정수를 입력하세요: ");
scanf("%lf",&a);
printf("두 번째 정수를 입력하세요: ");
scanf("%lf",&b);
fflush(stdin);
!!!
fflush(stdin)
는 미정의 동작(undefined behavior)을 유발합니다.쓰면 안 됩니다.
보는 족족 반박하고 있는데도 이 잘못된 정보가 퍼날라지는 속도를 따라잡을 수가 없군요. 책임감 좀 느끼셔야지요.
일반적으로
stdin
는 파이프든 디스크 파일이든 소켓이든 뭐든 될 수 있는데, 그 버퍼를 비운다는 게 어떻게 말이 됩니까.MSVC에서 콘솔 입력에 대해서는 바라시는 결과를 만들어준다는 거 저도 알고 있긴 합니다만, 고작 그런 이유로 범하기에는 undefined behavior의 대가가 무척 큽니다.
올바른 문제 분석은 아래와 같습니다.
프로그래머는 사용자가 숫자만 입력한다고 생각하겠지만, 그렇지 않습니다.
매번 숫자 입력을 마치고 사용자가 엔터를 누를 때마다 개행 문자(
'\n'
)도 같이 들어옵니다.단지
scanf
에서 숫자를 입력받는 서식 지정자("%d"
등.)가 공백 문자를 그냥 삼켜 버리기 때문에 정상동작할 뿐입니다.문자 하나를 입력받는 서식 지정자
"%c"
는 그렇게 동작하지 않습니다. 눈앞에 보이는 게 공백 문자이면, 공백 문자를 입력으로 받아와 버립니다.그러니
scanf
가 건너뛰는 게 아닙니다. 질문자님께서 의도하셨던 연산자 문자가 아닌, 그보다 앞서 들어온 개행 문자를 입력받고 넘어갔을 뿐입니다.이 의도치 않은 현상은 질문자님의 프로그램에서 두 가지 개선점을 제안합니다.
1. 수행할 연산을 입력하라고 했을 때, 사용자가 +-*/ 말고 다른 문자를 입력했을 때에 대한 에러 처리가 없군요.
이왕
switch
문을 쓰는 김에default
를 달아 주었으면 좋았을 텐데요. 거의 항상 그렇게 하는 게 좋은 습관입니다.프로그램에서 들어올 수 있는 모든 입력에 대해서 대처할 수 있는 견고한 코드를 짜는 법을 연습하세요. 나중에 다 도움이 됩니다.
2.
scanf("%c",&c);
가 공백 문자를 삼키고 공백 문자가 아닌 문자를 입력받도록 하고 싶으시면, 간단합니다.scanf(" %c",&c);
를 쓰세요."%c"
앞에 빈칸 하나 넣었습니다.scanf
류 함수의 서식 지정 문자열에서 빈칸의 역할을 대충 설명드리면, 대응되는 입력 지점에서 공백 문자를 최대한 삼키는 것입니다.scanf
의 정확한 동작에 대해 관심있으시면 레퍼런스 참조하시고요:http://en.cppreference.com/w/c/io/fscanf
이왕 레퍼런스 읽는 김에
fflush
를 입력 스트림에 대해 쓰면 어떻게 되는지도 숙지해 두세요:http://en.cppreference.com/w/c/io/fflush
마지막으로 한 가지 더. 변수 a와 b는
int
형인데,scanf
의 서식 지정자는double
을 받는 것을 사용하시는군요. 어느 한 쪽으로 통일하시지 않으면 절대 의도하신 대로 안 동작할 겁니다.감사합니다..
여태 잘못알았던 정보를 알게됬네요...
참고로 부언하자면 scanf()만 쓰는 것 외에
참고로 부언하자면 scanf()만 쓰는 것 외에 gets() (buffer overflow를 고려한다면 fgets()) + sscanf() 조합 사용도 고려해 보세요. gets()는 끝의 '\n' 을 자동으로 제거해 줍니다만 buffer overflow가 있을 수 있습니다. fget()로 받고 받은 문자열 끝의 '\n' 을 제거하면 sscanf() 로 오류없이 값들을 저장할 수 있습니다.
또 C++에서는 getline() 함수 사용도 고려해 볼수 있습니다. getline과 sscanf()를 쓰면 됩니다.
댓글 달기