모바일 오유 바로가기
http://m.todayhumor.co.kr
분류 게시판
베스트
  • 베스트오브베스트
  • 베스트
  • 오늘의베스트
  • 유머
  • 유머자료
  • 유머글
  • 이야기
  • 자유
  • 고민
  • 연애
  • 결혼생활
  • 좋은글
  • 자랑
  • 공포
  • 멘붕
  • 사이다
  • 군대
  • 밀리터리
  • 미스터리
  • 술한잔
  • 오늘있잖아요
  • 투표인증
  • 새해
  • 이슈
  • 시사
  • 시사아카이브
  • 사회면
  • 사건사고
  • 생활
  • 패션
  • 패션착샷
  • 아동패션착샷
  • 뷰티
  • 인테리어
  • DIY
  • 요리
  • 커피&차
  • 육아
  • 법률
  • 동물
  • 지식
  • 취업정보
  • 식물
  • 다이어트
  • 의료
  • 영어
  • 맛집
  • 추천사이트
  • 해외직구
  • 취미
  • 사진
  • 사진강좌
  • 카메라
  • 만화
  • 애니메이션
  • 포니
  • 자전거
  • 자동차
  • 여행
  • 바이크
  • 민물낚시
  • 바다낚시
  • 장난감
  • 그림판
  • 학술
  • 경제
  • 역사
  • 예술
  • 과학
  • 철학
  • 심리학
  • 방송연예
  • 연예
  • 음악
  • 음악찾기
  • 악기
  • 음향기기
  • 영화
  • 다큐멘터리
  • 국내드라마
  • 해외드라마
  • 예능
  • 팟케스트
  • 방송프로그램
  • 무한도전
  • 더지니어스
  • 개그콘서트
  • 런닝맨
  • 나가수
  • 디지털
  • 컴퓨터
  • 프로그래머
  • IT
  • 안티바이러스
  • 애플
  • 안드로이드
  • 스마트폰
  • 윈도우폰
  • 심비안
  • 스포츠
  • 스포츠
  • 축구
  • 야구
  • 농구
  • 바둑
  • 야구팀
  • 삼성
  • 두산
  • NC
  • 넥센
  • 한화
  • SK
  • 기아
  • 롯데
  • LG
  • KT
  • 메이저리그
  • 일본프로야구리그
  • 게임1
  • 플래시게임
  • 게임토론방
  • 엑스박스
  • 플레이스테이션
  • 닌텐도
  • 모바일게임
  • 게임2
  • 던전앤파이터
  • 마비노기
  • 마비노기영웅전
  • 하스스톤
  • 히어로즈오브더스톰
  • gta5
  • 디아블로
  • 디아블로2
  • 피파온라인2
  • 피파온라인3
  • 워크래프트
  • 월드오브워크래프트
  • 밀리언아서
  • 월드오브탱크
  • 블레이드앤소울
  • 검은사막
  • 스타크래프트
  • 스타크래프트2
  • 베틀필드3
  • 마인크래프트
  • 데이즈
  • 문명
  • 서든어택
  • 테라
  • 아이온
  • 심시티5
  • 프리스타일풋볼
  • 스페셜포스
  • 사이퍼즈
  • 도타2
  • 메이플스토리1
  • 메이플스토리2
  • 오버워치
  • 오버워치그룹모집
  • 포켓몬고
  • 파이널판타지14
  • 배틀그라운드
  • 기타
  • 종교
  • 단어장
  • 자료창고
  • 운영
  • 공지사항
  • 오유운영
  • 게시판신청
  • 보류
  • 임시게시판
  • 메르스
  • 세월호
  • 원전사고
  • 2016리오올림픽
  • 2018평창올림픽
  • 코로나19
  • 2020도쿄올림픽
  • 게시판찾기
  • 오유인페이지
    개인차단 상태
    볼살미나님의
    개인페이지입니다
    가입 : 13-06-22
    방문 : 3033회
    닉네임변경 이력
    회원차단
    회원차단해제
    게시물ID : programmer_10129
    작성자 : kosi
    추천 : 3
    조회수 : 3963
    IP : 118.37.***.207
    댓글 : 9개
    등록시간 : 2015/05/16 14:48:59
    http://todayhumor.com/?programmer_10129 모바일
    scanf... 그것이 알고 싶다!
    쓰다보니 쓸 데 없이 길어졌네요..
    바쁘신 분은 세줄요약만 보셔도 됩니다....

    ------------------------------

    과제 때문인지 업무 때문인지는 모르겠지만,
    C언어의 scanf 함수 사용에 대한 질문 글이 꾸준히 올라오네요. ^^;

    사실, scanf 를 업무용 프로그램에서 쓰는 일은 '거의' 라고 쓰고 '네버'라고 읽음 없습니다.
    왜냐 하면, 여러 질문에 나와 있는 '그 문제점들' 때문이죠.. ㅋㅋ.
    그리고, scanf 함수의 실제 구현과 동작은 각 시스템(Unix/Linux/Windows...)별로 다르고,
    컴파일러별로 다릅니다. C 표준에 정의된 사양만 그것에 부합하도록 같을 것이고, undefined behavior는 제조사마다 다를 겁니다.

    아무튼, 저도 scanf 질문글이 올라올 때마다,

    "뭐, 또, 엔터키 입력된 것 버퍼에서 안지워서 그렇겠지..."

    요정도 생각하고 들어 옵니다. 그리고 실제로 예지력 상승을 확인하고 나가죠...

    그러다 문득, 정말로 scanf 가 어떤 짓을 하도록 표준에 정의되어 있는 걸까...
    왜 그따위로 만들어서 여러 착한 사람들을 못살게 굴까 궁금해지기 시작했습니다.

    그래서, 일단, 소스코드를 좀 봐야겠다... 싶어서 찾아 봤죠.
    물론 시스템별로 구현이 다르니, scanf 소스코드도 여러 버전이 있습니다.
    그리고 요기 http://mirror.fsf.org/pmon2000/3.x/src/lib/libc/scanf.c 에는 좀 간략한 버전이 있더군요.

    좀 읽어 보려다가... 금세... 아몰랑.. 시전..
    뭐 소스를 꼭 이해해야 하는 건 아니잖아, 어차피 시스템마다 구현도 다른 걸... 이라는 자기합리화... -_-;;

    뭐, 아무튼, scanf 를 쓰면서 오는 혼란 중 가장 큰 것은,
    scanf 가 input buffer 를 '비울 때도 있고 안비울 때도 있기' 때문이라고 봅니다.
    게다가, scanf 의 표준에는 scanf 가 동작하다가 예외를 만났을 때의 상황을 일일이 정의하지 않고 있기 때문에,
    Windows/Linux/Unix/Mac 등등에서 서로 다른 시스템과 컴파일러를 사용하면서
    서로 묻고 답하는 와중에, 또다시 혼란이 생기고... 하여... 문제가 더 복잡해 지지 않았나... 마.. 그런 생각이 듭니다.

    흔히 scanf 관련 질문 올라올 때는 아래와 같은 패턴이죠:

    scanf("%d", &var1);
    printf("%d\n", var1);

    scanf("%d", &var2);
    printf("%d\n", var2);

    저기서, 첫번째 scanf에 입력을 했는데 왜 두 번째 scanf가 실행이 안되고 쭉 지나가 버리는가...하는 것이 가장 많지요?
    거기에 대한 답은 여러분도 익히 아시다시피 첫번째 scanf 문에서 입력을 할 때,
    마지막에 enter 를 넣은 것이 input buffer에 남아 있어서 그렇다. 그러니 아래와 같이 고쳐라..는 겁니다.

    scanf("%d", &var1);
    printf("%d\n", var1);

    getchar();

    scanf("%d", &var2);
    printf("%d\n", var2);

    요렇게 하면 해결이 된다! 맞습니다. 하지만, 예외처리가 완전히 된 것은 아닙니다.
    만약, 첫 번째 scanf 함수에서 사용자가 숫자가 아닌 문자를 '여러 개' 입력하면,
    또는 숫자와 문자를 합쳐서 11aaaa 와 같이 입력하면 또 다른 예외상황이 발생하게 됩니다.

    그래서, 입력을 받고 나면 무조건 버퍼를 비워라!
    라는 뜻으로 아래와 같이 하는 방법도 제시합니다.

    scanf("%d", &var1);
    printf("%d\n", var1);

    scanf("%s", str);

    scanf("%d", &var2);
    printf("%d\n", var2);

    요렇게 하면, 입력 버퍼가 비워지는 것은 맞습니다. 대부분의 경우 동작도 잘 될겁니다.
    다만, 저기서 사용자가 아주 긴.. 문자열을 입력하게 되면, 즉, str 이라는 버퍼의 크기를
    넘는 문자열을 입력하게 되면, 또 다시 예외상황이 발생하게 됩니다.

    그래서 이번에는, scanf로 비우지 말고, 아래와 같이 비워라... 하는 방법도 있습니다.

    scanf("%d", &var1);
    printf("%d\n", var1);

    fflush(stdin);

    scanf("%d", &var2);
    printf("%d\n", var2);

    요렇게요. 근데, 문제가 있습니다.
    fflush 라는 함수는 output buffer 에 있는 것을 모두 해당 stream으로 보내버리라는 것이지 (변기에서 물 내리는 것 처럼요)
    input stream에 대해서 동작하도록 C 표준에 있지는 않은 것 같습니다. (참조: http://c-faq.com/stdio/stdinflush2.html)
    그런데, 더 큰 문제는, fflush(stdin) 이라는 함수가 어떤 시스템 환경(아마도 Windows)에서는 동작하기도 하는 모양입니다??? (참조: https://kldp.org/node/29034)

    그리고, scanf("%d", &var) 등으로 읽을 때,
    어떤 시스템에서는 숫자 입력하고 난 후 'enter'를 누른 것을 input buffer에서 없애버리고,
    어떤 시스템에서는 남겨두고.. 하니까 이게... 더 혼란이 오는 것 같습니다.
    그리고, 이건 순전히 제 추측인데요.
    Windows 와 Linux 에서 개행(New Line)을 처리하는 문자가 다릅니다. 아시죠?
    Windows : 0D0A (Carriage-Return + Line-Feed)
    Linux/Unix/Mac : 0A
    요렇게 다른데요, Windows(또는 DOS)에서의 scanf는 0D는 읽어서 없애지만,
    0A는 남겨두는 것 같습니다.
    그러니, linux등에서 잘 되던 소스가 window에서 실행하면 이상하게 안되는 현상이 발생하기도 할 것이고요...

    그런데, 실제로 VisualC/C++ 등에서 구현된 scanf 의 소스코드를 보지 않았기 때문에,
    0D만 읽어서 없애고, 뒤따라오는 0A는 내버려 두는 일을 실제로 하는 지는 확인되지 않았습니다.

    scanf에 대해서 또하나 아셔야 할 것은,
    input stream에서 format에 지정된 타입의 값을 읽지 못하면 input stream buffer를 비우지 않는다는 것인데요,
    사실 이렇게 말하는 것 보다는 아래와 같이 말하는 것이 더 정확할 겁니다.
    "Input Stream에서 format에 지정된 type의 값을 읽게 되면 해당 값을 읽을 때까지의 버퍼는 비운다" 가 맞을 겁니다.
    무슨 말인고 하면,

    scanf("%d", &var); 로 사용자 입력을 읽을 때, 사용자가 입력을:

    1) 1234
    2) abcd
    3) ab12
    4) 12ab

    의 네 가지 경우가 있다고 가정하면,
    ----var에 들어가는 값------버퍼에 남아있는 문자---
    1) ==> 1234 ________________(없음)
    2) ==> (없음)________________abcd
    3) ==> (없음)________________ab12
    4) ==> 12 ___________________ab
    와 같이 된다는 겁니다.
    위에서 %d 로(즉, 숫자) 읽으라고 했으니, scanf는 input buffer에서 숫자를 찾습니다.
    1)의 경우에는 숫자가 찾아졌으므로 읽어서 변수에 할당하죠, 그리고 읽어낸 값을 inuput buffer에서 지웁니다.
    2)의 경우에는 숫자가 없으므로 변수는 변동되지 않지만, abcd 라는 문자는 '여전히' input buffer에 남아 있습니다.
    3)의 경우에도 2)와 다를 바 없습니다.
    4)의 경우에는 먼저 들어 온 숫자 12를 읽고 그 다음 문자(ab)를 만나게 되어서 12만 값을 넣고, 버퍼에서 12를 지우고, ab는 남겨 놓습니다.

    자, 이제 거의 다 왔네요 ^^;
    scanf 의 함수 이름이, SCAN 이잖아요... getInput 이나 readInput 이 아니고...
    그 말은, 뭔가를 scan....한다는 뜻이겠죠? 즉, input buffer를 scan 한다는 겁니다.
    scanf는 input buffer의 내용을 scan하면서, 주어진 format에 지정된 data-type에 matching되는 값을 찾아서
    주어진 변수에 할당을 하는 일을 하는 것이지, 단순히 키보드를 입력 받아서 그것을 실시간으로 변환하는 것이 아니기 때문에,
    이름을 get...이나 read..가 아닌 scan으로 지은 것이 아닌가.. 합니다.

    scan.jpg

    그럼 어떻게 scanf를 써야 하는가...?

    우선, 입력을 받기 위해서 scanf를 쓸 때는,
    실제로 scanf가 입력을 제대로 받았는지 확인하는 것이 가장 기본일 것 같습니다.

    scanf는 int형의 return 값이 있는데, format에 지정된 대로 값을 읽은 결과, 성공적으로 읽어서 변수에 저장한 갯수를 리턴합니다.

    ret = scanf("%d%f%c", &v1, &v2, &v3);

    위의 경우, scanf를 통해서 성공적으로 읽어 들인 값이 1개인지, 2개 또는 3개인지에 따라,
    ret의 값이 정해지게 됩니다. 물론, 하나도 못읽어들였다면 ret의 값은 0이 되겠죠.
    따라서, scanf의 리턴값과 v1/v2/v3 등의 변수의 값을 조사해서,
    적절한 예외 처리와 조치를 취하는 것이 좋을 것 같습니다.

    그리고, 여러 번의 scanf 함수 호출로, 사용자로부터 입력을 받아야 할 경우에는,
    input buffer에 남아 있는 white space나 개행문자, 또는 필요없이 남아 있는 문자들을 잘 제거해 주는 것이 필요하고요,
    특히나, Windows/Dos 에서는 엔터키를 칠 때 0D0A 라는 두개의 캐릭터가 input stream buffer에 들어가기 때문에,
    0A가 남아서 다음번 scanf 입력에서 원치않는 결과를 초래하는 것을 잘 방지해야 한다고 봅니다.

    그래서,
    10개의 정수를 입력받는 프로그램을 scanf를 써서 구현할 때,
    가장 이식성이 좋게 만든다면,

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    #include <stdio.h>
     
    int main()
    {
        int i;
        int c;
     
        i = 0;
        do
        {
            printf("Input Number[%d]: ",i);
     
            switch(scanf("%d",&c))
            {
                case 1:
                    printf("Input: %d\n",c);
                    i++;
                    break;
                default:
                    printf("No Integer Found\n");
                    printf("Check Your Input: >>>");
                    while((c = getchar()) != '\n' && c != '\r' && c != EOF) printf("%c",c);
                    printf("<<<\n");
                    break;
            }
        }
        while(i<10);
     
        return 0;
    }
     
    cs

    위와 같이, scanf의 리턴값을 조사해서 값을 제대로 읽어들이지 못했을 경우에는 input buffer를 비우도록 하는 것이 좋을 것 같습니다.

    결론 (세줄 요약)

    1. scanf를 여러 번 호출 할때, input buffer를 잘 지우자! (특히 Windows에서 0A 값이 남아서 문제가 자주 된다!)
    2. scanf는 입력 버퍼를 'SCAN' 하고, 원하는 형식의 값이 있으면 버퍼를 비우지만, 아니면 버퍼를 비우지 않고 그대로 놔둔다!
    3. scanf도 리턴 값이 있다. 리턴값을 잘 활용하자!

    입니다... 그리고 참고로, fflush(stdin) 함수는 DOS에선 잘 동작하지만 유닉스 계열에선 동작하지 않는다는 것도요~

    마지막!
    scanf 함수는 실제 업무에서는 '전혀' 쓰이지 않습니다... 고로 지금까지 전 뻘짓한겁니다...ㅠㅠ
    kosi의 꼬릿말입니다
    You never know what you're gonna get

    이 게시물을 추천한 분들의 목록입니다.
    [1] 2015/05/16 15:04:36  220.87.***.93  피소금  81642
    [2] 2015/05/16 15:09:56  112.155.***.84  파송송드립탁  331483
    [3] 2015/05/17 08:11:40  221.156.***.183  뻐꾸기77  597022
    푸르딩딩:추천수 3이상 댓글은 배경색이 바뀝니다.
    (단,비공감수가 추천수의 1/3 초과시 해당없음)

    죄송합니다. 댓글 작성은 회원만 가능합니다.

    번호 제 목 이름 날짜 조회 추천
    23
    그냥 기념으로 남기려고... [6] 창작글베스트금지베오베금지본인삭제금지외부펌금지 볼살미나 24/03/30 12:25 491 6
    22
    오늘을 위해 이렇게 조절했다 [8] 볼살미나 20/01/01 00:12 2101 30
    21
    나정모사지미다채쯔 [6] 볼살미나 17/08/15 09:31 194 10
    20
    두부 움짤 폰배경 적용 결과... [2] kosi 17/03/22 13:44 110 10
    19
    줸장, 쳇, ㅆ... HD 530... HDMI 안돼요 [3] kosi 16/05/25 09:27 61 2
    18
    HD530 마우스 커서 애니매이션이 깔끔하지 못한데요 [2] 본인삭제금지 kosi 16/05/17 11:37 71 0
    17
    PHP 문자열 증가 연산자 - 오늘 첨 알았네요 ㅋ [3] kosi 16/05/11 15:41 50 4
    16
    지르고 나서 어제 조립했습니다. [12] kosi 16/05/05 10:32 136 11
    15
    질렀습니닼ㅋㅋㅋㅋㅋ [4] kosi 16/05/04 18:02 98 4
    14
    한달간 미룸을 완료하고 지르러 가렵니다. (견적 ^^) [12] kosi 16/05/04 09:35 108 1
    13
    노트북에 윈도우10 설치하고 슬립모드나 종료 후에도 배터리 광탈이신 분들 [3] kosi 16/04/24 13:31 88 3
    12
    개발용 PC 견적 한번 봐주세요 [5] 베스트금지본인삭제금지 kosi 16/04/06 13:48 68 0
    11
    MS 가 자마린(Xamarin)을 무료로 한다고 하네요 [6] kosi 16/04/01 09:20 102 0
    10
    트라이 포스 삼총사 - 간단 리뷰 (스포??주의) kosi 16/02/01 11:04 20 1
    9
    트라이포스 삼총사 오늘 올듯... [2] kosi 16/01/27 13:17 45 1
    8
    뭘 먹고 싶긴한데... [5] kosi 15/09/04 19:40 92 0
    7
    모바일에서 프게 아이콘 안보이는거요 [2] kosi 15/07/28 21:05 34 0
    6
    시간이 양자화되어 있다면, 시간 사이의 간격을 느끼지는 못하겠지요? [16] kosi 15/07/17 10:05 64 1
    5
    발전소에서는 전자를 만들어 내는 건가요? [14] 본인삭제금지 kosi 15/07/07 10:46 62 2
    4
    2년 반 된 iPhone 4S 가 충전할 때 자꾸만 리부팅 합니다 [4] kosi 15/06/22 10:56 24 0
    3
    도대체 뭐가 맘에 안드는 게냐... (이클립스 주의) [3] 창작글 kosi 15/06/02 09:33 34 0
    2
    질문) 이상한 제목의 파일이 다운로드가 됩니다 [5] 본인삭제금지 kosi 15/05/27 20:39 31 0
    scanf... 그것이 알고 싶다! [9] kosi 15/05/16 14:48 57 3
    [1]
    단축키 운영진에게 바란다(삭제요청/제안) 운영게 게시판신청 자료창고 보류 개인정보취급방침 청소년보호정책 모바일홈