Project Hub

12. 입출력 (istream, ostream) 본문

C++/c++ basic

12. 입출력 (istream, ostream)

safy 2022. 12. 21. 14:03
728x90
반응형

이전 글

2022.12.21 - [C++/c++ basic] - 11. virtual 함수와 다형성

 

11. virtual 함수와 다형성

이전 글 2022.12.21 - [C++/c++ basic] - 10. 업 캐스팅 & 다운 캐스팅 10. 업 캐스팅 & 다운 캐스팅 이전 글 2022.12.21 - [C++/c++ basic] - 9. 전위/후위 증감 연산자 오버로딩 & 첨자 연산자 오버로딩 9. 전위/후위

projecthub.tistory.com


C++ 의 입출력 라이브러리는 아래와 같이 구성되어있다.

입출력 라이브러리 구조


실제로 입력을 수행하는 클래스는 istream 클래스다. 

istream 클래스

operator>> 가 isteam 클래스에 정의되어 있다.


std::cin >> a; 와 같은 형태로 사용할 수 있다.


여러 타입에 대해서도 정의가 되어있고, 아래와 같은 방법을 통해 사용자가 임의로 정의도 가능하다.

istream& operator>>(istream& in, std::string& s)
{
    //// 구현
}


operator>> 의 또라른 특징은, 모든 공백문자 (띄어쓰기, 엔터, 탭 등)을 입력시에 무시해버린다.

#include <iostream>
#include <string>
 
int main()
{
    std::string str;
 
    while (true)
    {
        std::cin >> str;
        std::cout << "word : " << str << std::endl;
    }
 
    return 0;
}
 
// 출력
this is a long sentence
word : this
word : is
word : a
word : long
word : sentence

 

위와 같은 특징은 반드시 주의해야 할 점이 있다.

 

operator>> 사용 시 주의해야 할 점

아래와 같이 정의된 코드에서, 숫자가 아닌 문자를 사용자가 입력 할 경우, 의도하지 않은 결과가 반환이 된다.

문자를 입력할 경우, t에 0이 담기게 되는 것을 확인했다. 

따라서 무한 루프에 빠지게 된다.

#include <iostream>
#include <string>
 
int main()
{
    int t;
 
    while (true)
    {
        std::cin >> t;
        std::cout << "입력 : " << t << std::endl;
        if (1 == t) break;
    }
 
    return 0;
}
 
// 문자를 입력할 경우, t에 0이 반환된다.
// 그리고 0이 계속 출력되게 된다. 무한루프에 빠짐

 

위와 같이 무한루프에 빠지는 원인은 다음과 같다.

ios 클래스에서 스트림의 상태를 관리하는 4개의 플래그가 존재한다.


goodbit: 스트림에 입출력 작업이 가능할 때
badbit: 스트림에 복구 불가능한 오류 발생 시
failbit: 스트림에 복구 가능한 오류 발생 시
eofbit: 입력 작업 시에 EOF 도달 시


문제가 발생한 상황에서 현재 스트림 버퍼에 들어가 있는 문자열은 'c\n' 이다. (문자 'c' 를 입력했다고 가정)


이때의 플래그는 failbit 가 켜지게 되고, 입력 값을 받지 않고 리턴해버린다.


'c\n'가 남아있는 상태에서 리턴을 해버렸기 때문에 버퍼에 남아있는 'c\n'를 다음에 또 읽고, 또 읽게 되는 문제가 발생되어 무한루프에 빠진다.


문제를 해결하기 위해서는 다음과 같이 코드를 수정하면 된다.

#include <iostream>
#include <string>
 
int main()
{
    int t;
 
    while (std::cin >> t)
    {
        std::cout << "입력 : " << t << std::endl;
        if (0 == t) break;
    }
 
    return 0;
}

 

ios 에 정의되어 있는 함수들 중에 다음과 같은 함수가 있다.

operator void*() const;


이 함수는 ios 객체를 void* 로 반환해준다.

이때 NULL 포인터가 아닌 값을 리턴하는 조건은, failbit, badbit 가 off 일 때다.

즉 스트림에 정상적으로 입출력 작업을 수행 할 수 있을 때 NULL이 아닌 값을 반환하게 되는 것이다.

위의 방법으로 문제는 해결 가능하지만, 입력을 계속 진행할 수 없다.

이유는, cin에 fail 비트가 켜진 상태이기 때문이다.

따라서 아래와 같이 goodbit로 초기화를 진행해주고, 

 

ignore 함수를 통해 개행문자가 나올 때 까지 무시할 수 있도록 하면 된다.

#include <iostream>
#include <string>
 
int main()
{
    int t;
 
    while (true)
    {
        std::cin >> t;
        std::cout << "입력 : " << t << std::endl;
        if (std::cin.fail())
        {
            std::cout << "fail" << std::endl;
            std::cin.clear();                   // goodbit로 초기화
            std::cin.ignore(100, '\n');         // 최대 100자 까지 개행 문자가 나올 때 까지 무시.
                                                // 100자 이상이 입력되어 있는 경우, 여러 번 호출 될 수 있다.
        }
 
        if (1 == t) break;
    }
 
    return 0;
}



728x90
반응형

'C++ > c++ basic' 카테고리의 다른 글

14. template  (0) 2022.12.21
13. 파일 입출력  (1) 2022.12.21
11. virtual 함수와 다형성  (0) 2022.12.21
10. 업 캐스팅 & 다운 캐스팅  (0) 2022.12.21
9. 전위/후위 증감 연산자 오버로딩 & 첨자 연산자 오버로딩  (0) 2022.12.21
Comments