C++의 입출력은 ios_base라는 클래스가 담당한다. 이는 10진수 16진수 혹은 자료형 타입에 따른 처리를 결정한다.

ios클래스는 스트림 버퍼를 초기화하며, 이때 버퍼는 데이터를 내보내거나 받아들이기전에 놔둘 수 있는 임시 저장공간이다.
다음은 istream 클래스다. cin>>a cout<<a를 생각해보면 a는 어떤 타입이 들어가도 정상적으로 입출력 되던것이 떠오를 것이다. 이에 대한 오버라이딩이 되어있는 클래스가 istream이다.
istream의 cin은 공백을 구분자로 동작하는 입력방식이기에, 공백을 만나면 입력을 종료하고, 그 이전의 단어만 저장한다. 즉 단어 단위로 입력을 받는다.
int main()
{
std::string s;
std::cin>>s;
std::cout<<"word:"<<s<<std::endl;
}
input -> this is a long sentence
word:this
해당 코드의 cout결과는 this에서 종료된다. 즉 공백을 기준으로 this까지는 출력해내지만, 버퍼의 이동은 is쪽으로 이동하는 것으로 끝을 내는 것이다.
(getline은 이와 달리 공백을 포함하여 버퍼를 처리리하기에 한번에 출력해낼 수 있다.)
int main()
{
std::string s;
while(true)
{
std::cin>>s;
std::cout<<"word:"<<s<<std::endl;
}
}
///
input -> this is a long sentence
this is a long sentence
word:this
word:is
word:a
word:long
word:sentence
while문으로 바뀔 경우 공백을 기준으로 각 단어들이 출력된다. 여기서 의문을 가지는 이도 있을 것이다.
첫번째 while의 버퍼가 is로 이동하는 것은 알겠는데, 왜 is는 cin을 거치지 않고 바로 출력되는가?
이는 버퍼의 특징때문이다. 입력버퍼는 사용자가 입력한 데이터를 저장하고, 프로그램이 필요한만큼 꺼내 쓴다. 즉 한 번 입력한 문자열은 버퍼에 계속 남아있다.
앞선 예시처럼, this is a long sentence의 경우 두번째 루프가 시작되면 cin>>s는 다시 입력을 받는 것이 아닌, 입력 버퍼에 남아있는 데이터 is a long sentence라는 데이터들을 바로 처리한다.
버퍼가 비워질때 까지는 입력을 새로 받지 않고, 남은 데이터를 계속 처리하게 된다는 것이다.
앞서말한 ios클래스는 스트림버퍼를 관리한다고 하였다. 스트림에는 4개의 플래그가 있는데, 이 플래그를 통해 스트림의 상태를 알 수 있다.
버퍼를 받는 도중에 오류가 생기면 failbit가 켜지게 된다. 아래 예시를 보자.
int main() {
int n;
while (std::cin >> n) {
std::cout << "input :: " << n << std::endl;
}
}
///
3
input :: 3
4
input :: 4
s
int형으로 정의된 inputdata는 3과 4를 받을때는 이상이 없었으나 정의되지 않은 char타입을 받으니 무한루프가 돌아버린다. failbit가 켜진 것이다.
failbit가 켜지게 되면 입력을 더 이상 받지 않게 되므로 프로그램이 종료는 되지 않으나, 더 이상 입력을 받지 않아 무한루프에 들어가버린 것이다.
이를 방지하기 위한 방법은 간단하다.
int main() {
int n;
while (std::cin >> n) {
std::cout << "input :: " << n << std::endl;
if (n == 0) break;
}
}
무한 루프에 빠지지 않고 break되서 나올 수 있다.
failbit가 이처럼 0으로 평가되는 이유는 cin에서 알 수 있는데, cin은 boolean context다. 즉 데이터를 성공적으로 처리하면 true, 실패하거나 EOF에 다다르게 되면 false를 반환한다는 것이다.
때문에 false를 의미하는 0이 되었을때 if문에 들어갈 수 있다는 것이다.
덧붙여서 failbit의 경우에도, 계속해서 다음 입력데이터를 받고 싶다면 .fail, .clear .ignore 를 사용하면 되나, 여기서 다루진 않으려고 한다.
int main() {
// 파일 읽기 준비
std::ifstream in("test.txt");
std::string s;
if (in.is_open()) {
in.seekg(0, std::ios::end);
int size = in.tellg();//사이즈 확인
s.resize(size);
in.seekg(0, std::ios::beg);
in.read(&s[0], size);
std::cout << s << std::endl;
}
return 0;
}
골자는 간단하다. c에서도 그랬지만, c++역시 파일을 읽기 위해서는 위치지정자를 이동시켜줘야 한다. 핵심인 read()함수를 보면 인자를 두개 받는다. 각각 저장할 공간과 size다.
때문에 위치지정자를 두번 이동시킨다. 처음은 end로 이동시켜 사이즈 확인을, 두번째는 처음으로 이동시켜 read를 할 수 있게끔 한다.
개행문자(엔터)가 나올때까지 입력을 받는 getline을 사용하면 좀 더 간단해진다.
while (in) {
in.getline(buf, 100);
std::cout << buf << std::endl;
}
다음은 파일에 쓰기이다. 이 역시 어렵지 않다.
int main() {
std::ofstream out("test.txt");
//out결과를 내야하기에 ofstream을 사용한다.
std::string s;
if (out.is_open()) {
out << "write this!<<std::endl;
}
return 0;
}
cin처럼 방향이 <<임에 주의하자.