scanf 건너뜀

한동수@Facebook의 이미지

#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;
}
}

kik9459의 이미지

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을 받는 것을 사용하시는군요. 어느 한 쪽으로 통일하시지 않으면 절대 의도하신 대로 안 동작할 겁니다.

kik의 이미지

여태 잘못알았던 정보를 알게됬네요...

라스코니의 이미지

참고로 부언하자면 scanf()만 쓰는 것 외에 gets() (buffer overflow를 고려한다면 fgets()) + sscanf() 조합 사용도 고려해 보세요. gets()는 끝의 '\n' 을 자동으로 제거해 줍니다만 buffer overflow가 있을 수 있습니다. fget()로 받고 받은 문자열 끝의 '\n' 을 제거하면 sscanf() 로 오류없이 값들을 저장할 수 있습니다.

또 C++에서는 getline() 함수 사용도 고려해 볼수 있습니다. getline과 sscanf()를 쓰면 됩니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.