모바일 오유 바로가기
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도쿄올림픽
  • 게시판찾기
  • 오유인페이지
    개인차단 상태
    침팬지대장님의
    개인페이지입니다
    가입 : 11-09-22
    방문 : 4590회
    닉네임변경 이력
    회원차단
    회원차단해제
    게시물ID : programmer_21261
    작성자 : 침팬지대장
    추천 : 9
    조회수 : 3048
    IP : 180.70.***.230
    댓글 : 2개
    등록시간 : 2017/08/24 15:36:15
    http://todayhumor.com/?programmer_21261 모바일
    C/C++ 문자열을 입력받는 12가지 방법
    옵션
    • 펌글
    과정이 재미있어서 퍼온 펌글입니다.

    ==================== 

    이 글은 제가 예전에 제가 활동하고 있는 학교 동아리에 "문자열을 입력받는 12가지 방법"이라는 제목으로 올렸던 내용을 재 편집한 것입니다.



    C/C++을 이용한 문제해결의 한 단편을 제시하기 위해 "표준입력으로부터 입력받은 길이를 알 수 없는 문자열 저장하기"라는 아주 전형적인 문제의 예를 들어 보겠다.

    C --> C++ 을 배운 표준적인(?) 커리큘럼을 따른 프로그래머라면 표준입력(키보드)으로 문자열을 입력받을 때 다음과 같은 C스타일의 표현은 모두 알고 있을 것이다.

    방법1)
    char s[LENGTH];
    scanf( "%s", s );


    누구나 알고 있고, 또한 별 무리없이 원하는 결과를 낸다는 점에서 만족스럽다.
    그러나 다음과 같은 면에서 문제가 있다.
    1> scanf()함수는 인자로 주어지는 형식지정자(format specifier)을 파싱해야 하는 오버헤드가 따른다.
    2> 공백문자가 나타나면 읽기를 중단한다.
    3> 형 안정성을 보장받을 수 없다 ( "%s" 대신 "%d"로 오타라도 낸다면?)
    4> 그리고, 문자열의 예상되는 크기를 프로그래머가 알고 있어야 한다.

    1>,2>, 3> 문제를 해결하기 위해 다른 방법을 고려해 보자.

    방법2)
    char s[LENGTH];
    gets( s );


    C표준의 gets()함수는 문자열을 입력받는 거의 흠잡을데 없는 기능을 제공한다는 면에서는 아주 만족스럽다. scanf()와 같이 형식지정자를 파싱해야 하는 오버헤드도 없으며, 빈칸이 나오더라도 개행문자를 입력할때까지 끊임없이 입력받는다. 그러나 역시 다음과 같은 면에서 만족스럽지 못하다.

    "표준입력으로부터의 입력이 문자열 버퍼의 크기를 넘어가는 경우에는 어떤 결과가 따를지 예상할 수 없다."

    그렇다면 문제를 해결해 보자. 이 문제는 gets()함수가 버퍼의 크기를 전혀 알지 못한다는 것에서 비롯된다. 그렇다면 버퍼의 길이를 알아야 하는 함수를 사용해 보자.

    방법3)
    char s[LENGTH];
    fgets( s, LENGTH, stdin );


    이 fgets()함수는 파일로부터 문자열을 읽어들이는 함수이나, stdin이라는 표준입력에 대응하는 파일포인터를 사용함으로써 표준입력으로부터 문자열을 입력받는데도 사용할 수 있음을 상기하자. fgets()의 두번째 인자로 버퍼의 크기를 줌으로써 버퍼 오버플로우 문제는 해결할 수 있다. 그러나 다음과 같은 문제가 따른다.

    "fgets()함수가 리턴되더라도 모든 문자열이 입력된 것인지 알 수가 없다."

    이제부터 문제가 복잡해지기 시작한다. fgets()함수는 버퍼의 크기까지만 문자열을 읽기 때문에 단순히 함수가 리턴되었다는 것만으로는 아직 표준입력 스트림에 문자가 남아있는지 알 수가 없다. 따라서 추가적인 로직이 필요해진다.

    방법4)
    char s[LENGTH];
    char *t, *u;
    int size = 0;
    int len;
    do
    {
        s[LENGTH-2] = 0;
        fgets( s, LENGTH, stdin );
        len = strlen( s );
        size += len;

        u = malloc( size ); // (1)
        strcpy( u, t ); // ...
        free( t ); // (1)

        strcat( u, s );
        t = u;
    while( len == LENGTH-1 && s[LENGTH-2] != '\n' );


    상당히 복잡해 졌다. 더 깔끔하게 정리할 수도 있겠지만, 어쨋든 간단하기 구현하는 한에서 입력스트림으로부터의 문자열을 모두 저장하기 위한 코드임에는 분명하다. while루프는 차치하고라도, 루프 내부의 코드는 대부분 문자열 버퍼의 재할당을 위한 코드이다. 물론, (1) 부분은 realloc()으로 간단히 사용할수도 있다.

    방법5)
    char s[LENGTH];
    char *t = 0;
    int size = 0;
    int len;
    do
    {
        s[LENGTH-2] = 0;
        fgets( s, LENGTH, stdin );
        len = strlen( s );
        size += len;

        t = realloc( size );
        strcat( t, s );
    while( len == LENGTH-1 && s[LENGTH-2] != '\n' );


    아주 약간 정리가 되었다. 그러나, 여전히 루프 자체의 복잡성은 남아 있다. 왜 그럴까? 루프 내의 코드를 살펴보면 크게 두 부분으로 이루어져 있음을 알 수 있다. 입력스트림으로부터 받은 문자열을 임시 버퍼 s에 저장하는 부분이며, 나머지는 임시버퍼로부터받은 문자열을 완성된 문자열로 저장하는 부분이다. 이와같은 문자열 조작의 불편함은 전적으로 C에서의 문자열이 '문자열'이 아니라 '문자배열'이기 때문이다.

    위와 같은 문제를 해결하기 위해 그렇다면 이제부터 C++의 세계로 넘어가보자.
    C++에서 문자열을 입력받는 것은 위의 논의와 비슷하게 진행된다.

    방법6)
    char s[LENGTH]
    std::cin >> s;


    cin객체는 기본적으로 scanf()와 아주 비슷한 일을 한다. 그러나 여러가지 장점이 있다. 만약 s를 선언할때 잘못하여 int로 썼더라도 cin>>s;라는 문장을 컴파일하는 과정에서 컴파일러가 에러를 잡아주어 형 안정성을 보장해 준다.
    하지만 여전히 "공백문자에서 멈춤"문제는 남아 있다. 그렇다면 scanf()에서 gets()로 넘어갈때와 같은 고려를 해보자. 이번에 고려할 수 있는 것은 basic_istream클래스의 getline()메소드이다.
    (이제부터는 편의상 std 네임스페이스는 생략하도록 하겠다)

    방법7)
    char s[LENGTH];
    cin.getline( s, sizeof( s ) );


    getline()메소드는 gets()함수와 아주 비슷한 일을 하는 iostream클래스의 메소드이다. 차이점이라면 fgets()함수와 비슷하게 버퍼 사이즈를 인자로 받는 정도뿐이다. 역시 fgets()함수와 마찬가지의 문제점을 지니고 있다고 할 수 있겠다.
    그렇다면 fgets()에서 스트림을 모두 비우는 루틴을 고려해 보자.

    방법8)
    char s[LENGTH];
    char *t = 0;
    int size = 0;
    do
    {
        cin.clear()
        cin.getline( s, LENGTH );

        size += strlen( s );
        t = realloc( size );
        strcat( t, s );
    while( cin.fail() );


    어떨까? 물론.. (시험해보진 않았지만) 제대로 돌아갈 것 같긴 하다. 당신, 정말로 이걸로 만족하는가? C++은 객체지향의 세계이다. 저기서 객체라고는 cin밖에 쓰이지 않았다.
    이런 코드는 C를 배운 다음 C++로 옮겨가려는 사람이 쓰게되는 전형적인 스타일이라고 할 수 있겠다. 즉, C의 코드를 그대로 C++라이브러리로만 옮기는 것. 바로 그러한 오류의 전형이다.

    그럼 조금만 바꿔보자. 위에서 strcat()으로 문자열을 합치는 부분은 C++표준의 string클래스를 사용하면 간편하게 될듯하다.

    방법9)
    char s[LENGTH];
    string t;
    do
    {
        cin.clear()
        cin.getline( s, LENGTH );
        t += s;
    while( cin.fail() );


    어떤가? 루프 내부는 한결 깔끔해졌다. 버퍼의 재할당과 문자열 복사라는 주요한 기능을 캡슐화한 string클래스를 사용함으로써 코드의 절반을 절약하는 성과를 이루어 냈다.
    만족스러운가? 아니다. 여전히 뭔가가 어색하다. 그 이유는: 바로 string '객체'와 문자'배열'이 혼재하고 있다는, 스타일의 불일치이다. 사람의 언어로 따지자면, 모 디자이너처럼 명사는 영어로, 조사만 우리말로 붙여서 쓰는 것과 같은 아주 어색한 말투에 비유할 수 있겠다.
    그렇다면 입력버퍼로 사용하는 s가 문제이다. 위에서 말했듯이, s는 '문자배열'이지 '문자열'이 아닌 것이다. 그렇다면 s를 string객체로 대체할 수 있는 방법을 강구해야 한다.

    아마도, 여러분은 십중팔구 여기서 cin의 메소드 중에 string객체를 인자로 받는 멤버를 생각할 것이다. 그리고 도움말에서 검색을 시도하고는, 아마도, 자그마한 좌절을 경험하고는 '문자배열로만 입력받을 수밖에 없잖아!'라고 비명을 지르고는 말 것이다. 정말일까? 본인의 경험에 비추어 본다면, 검색 노력이 부족했다고 할수밖에 없겠다. cin은 istream클래스의 한 인스턴스이며, istream클래스로 검색해 본다면 조금 아래쪽에 istream_iterator라는 항목이 존재하는 것을 발견할 수 있을 것이다. istream_iterator에 대한 자세한 설명은 생략하겠지만, iterator패턴을 입력스트림에 대해 구현한 클래스템플릿이다.. 정도로만 일단 알아두자.
    그렇다면 istream_iterator를 사용할 경우, 방법9)과 유사한 동작을 하는 코드는 다음과 같이 바뀐다.

    방법10)
    string s( istream_iterator( cin ), istream_iterator() );


    어떤가? 경이적으로 코드가 줄어들었다. 위 코드는 지금까지 항상 속을 썩이던 문제, 즉, "사전에 예상되는 문자열의 길이 알기"라는 문제를 근본적으로 제거하였다.
    꽤나 만족스럽다. 그러나 문제가 있다. istream_iterator 템플릿은 입력을 받을때 operator>>을 사용하며, 결과적으로 cin >> XXX라는 동작을 반복하도록 되어 있는 이터레이터이다. 곧, 공백문자는 무시한다. 그래서 공백분자를 무시하지 못하도록 설정해보자.

    방법11)
    cin.unsetf( ios::skipws );
    string s( istream_iterator( cin ), istream_iterator() );
    cin.setf( ios::skipws );


    원하든 대로 동작하면서도 굉장히 깔끔한 코드를 손에 넣었다. 그러나, 문제가 있다. 바로 입력을 종료하기 위해서는 EOF캐릭터를 입력해야 한다는 것이다 (전통적으로는 ^Z를 입력함으로써 EOF캐릭터가 들어간다) 이는 istream_iterator는 기본적으로 파일스트림에 대해 사용하도록 되어 있는 클래스이기에 그러하다. 이걸 어떻게 해결해야 할까?

    그렇다면 다시 cin.getline()을 보자. 역시나 우리가 원하는 동작은 getline이 가장 유사하다. 그렇다면 도움말 검색창에 getline이라고 쳐 보자. 어떠한가? basic_istream의 멤버인 getline()메서드와 함께 전역 getline() 템플릿함수도 나타날 것이다. getline()템플릿함수의 자세한 사용법은 생략하고, 이 함수를 사용하여 문자열을 입력받는 전형적인 예는 다음과 같다.

    방법12)
    string s;
    getline( cin, s );


    어떤가? 원점으로 돌아온 느낌이 드는가? 아니다. 분명히 형태는 최초의 C버전의 코드와 굉장히 비슷하지만, 모든 것이 객체로 되어 있는 객체지향의 세계이며, 고질적인 "버퍼사이즈 미리알기"문제가 근본적으로 해결되었으며, 단 두줄밖에 안되는 깔끔한 코드이다.

    'C++스러운' 코드를 작성하기 위해서는 많은 해결방법을 고려해볼 필요가 있다는 점을 말해두고 싶다.
    출처 http://blog.naver.com/theuhm/100005060891

    이 게시물을 추천한 분들의 목록입니다.
    [1] 2017/08/24 16:42:32  114.199.***.69  이과출신  116492
    [2] 2017/08/24 17:59:46  110.76.***.6  キャスター  655684
    [3] 2017/08/24 21:19:25  114.202.***.230  내가니엡이다  94397
    [4] 2017/08/24 21:39:01  223.194.***.65  작은돼지  140557
    [5] 2017/08/25 00:00:43  14.50.***.211  REGENTAG  141650
    [6] 2017/08/25 01:25:35  112.165.***.105  아하실  732672
    [7] 2017/08/28 20:33:16  220.94.***.22  불편할듯  71500
    [8] 2017/09/03 19:49:20  121.66.***.106  비벨라곰팡이  49534
    [9] 2017/09/13 13:57:48  172.58.***.119  nc스테고  414704
    푸르딩딩:추천수 3이상 댓글은 배경색이 바뀝니다.
    (단,비공감수가 추천수의 1/3 초과시 해당없음)

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

    번호 제 목 이름 날짜 조회 추천
    438
    역대급 고속도로 통행료 인상 ㄷㄷ [2] 펌글 침팬지대장 23/09/29 17:27 1514 22
    437
    테슬라에서 나온 무선충전기 [7] 펌글 침팬지대장 23/09/26 19:23 2335 20
    436
    일벌이 여왕벌 행세하는 벌통 [10] 펌글 침팬지대장 23/09/24 17:20 1950 21
    435
    왕릉에선 금지인데…"왜 안 돼?" 못 말리는 '맨발 걷기'.jpg [15] 펌글 침팬지대장 23/09/23 09:25 2353 15
    434
    식당 밥이 맛있고 딸래미가 이쁘면 생기는 일 .jpg [11] 펌글 침팬지대장 23/09/23 09:17 3159 17
    433
    암사자들이 사냥갔을때 숫사자들의 임무 [7] 펌글 침팬지대장 23/09/23 09:04 2053 14
    432
    아깽이 도우개 [13] 펌글 침팬지대장 23/09/23 08:59 1689 18
    431
    강풀이 ㄹㅇ 실력파 작가인 이유 [7] 펌글 침팬지대장 23/09/23 08:53 3319 17
    430
    샤인머스캣 맛 없어진 이유.jpg [7] 펌글 침팬지대장 23/09/23 08:38 2735 17
    429
    우산을 펴서 말리면 안되는이유 [7] 펌글 침팬지대장 23/09/23 08:30 3083 17
    428
    배수관을 막고 자란 잡초 [22] 펌글 침팬지대장 23/09/22 13:51 2735 22
    427
    대통령실에서 올린 김명신 사진 [5] 펌글 침팬지대장 23/09/16 18:07 1032 17
    426
    (폭언주의)추적60분에 나온 레전드 민원 전화 [3] 펌글 침팬지대장 23/09/10 08:23 2054 7
    425
    K-예비군 레전드 사건 [2] 펌글 침팬지대장 23/09/08 17:05 1814 22
    424
    대한민국 자유민주주의 근황 [17] 펌글 침팬지대장 23/09/07 14:20 2799 25
    423
    요즘 미쳤다고 논란중인 신세계 정용진 근황 ㄷㄷ [6] 펌글 침팬지대장 23/09/07 06:29 5205 29
    422
    조선의 의르코스 근황.jpg [7] 펌글 침팬지대장 23/09/06 10:57 2459 17
    421
    이센스가 말하는 대마초, 마약 그리고 미디어 [10] 펌글 침팬지대장 23/09/05 14:53 2850 11
    420
    오늘자 한국형 집회 ㄷㄷㄷ [3] 펌글 침팬지대장 23/09/02 23:06 2205 32
    419
    분하지만 요즘 맞는말인 더킹 대사.jpg [31] 펌글 침팬지대장 23/08/30 14:51 2682 26
    418
    녹색 스프레이로 죽은 잔디 땜빵한 서울 월드컵경기장 [5] 펌글 침팬지대장 23/08/27 15:03 3018 16
    417
    일본대사관에 핵오염수 방규 규탄하는 끌려가는 대학생들 [2] 펌글 침팬지대장 23/08/24 15:53 674 17
    416
    멕시코에서 벌어진 천년에 한번 있을까 말까한 사건 [7] 펌글 침팬지대장 23/08/20 11:32 3379 25
    415
    칼부림 사건에 게임을 엮는 이유를 밝혀낸 G식백과.jpg [39] 펌글 침팬지대장 23/08/10 18:59 1689 19
    414
    잼버리) 지방직 공무원 주말 비상걸림...blind [2] 침팬지대장 23/08/05 13:53 2186 18
    413
    흉기난동 천룡인 권장국 등극 feat.판검새가 만들어가는 안전한 대한민국 [4] 펌글 침팬지대장 23/08/05 09:11 1800 17
    412
    [혐주의] 깊이 찔린 고양이 구조하기 [5] 펌글 침팬지대장 23/07/22 13:59 1119 13
    411
    17시에 드론으로 찍은 청주 궁평2지하차도 침수 사고 [5] 펌글 침팬지대장 23/07/15 23:57 1918 11
    410
    현재의 대한민국 [11] 펌글 침팬지대장 23/07/10 07:17 990 26
    409
    20대 남자 인생 쉽게 조지는법 [28] 펌글 침팬지대장 23/05/04 08:20 2959 22
    [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [다음10개▶]
    단축키 운영진에게 바란다(삭제요청/제안) 운영게 게시판신청 자료창고 보류 개인정보취급방침 청소년보호정책 모바일홈