백준

[백준 C++] 10951번 A+B -4

슬뷔 2023. 12. 20. 16:39

https://st-lab.tistory.com/257

 

[백준] 10951번 : A + B - 4 - [C++]

https://www.acmicpc.net/problem/10951 10951번: A+B - 4 두 정수 A와 B를 입력받은 다음, A+B를 출력하는 프로그램을 작성하시오. www.acmicpc.net 문제 이 전 문제인 A+B - 5와 문제가 같아보이나 이 번 문제는 유의해

st-lab.tistory.com

 

이 번 문제의 키 포인트는 문제를 자세히 보면 몇 개를 입력받는지 알 수 없다는 것이다.

 

이렇게 주어진 입력 파일만 갖고 입력을 받을 때 더이상 읽을 수 있는 데이터가 없는 경우 즉, 파일의 끝일 때 이를 EOF(End Of File) 이라고 한다.

 

위 문제를 본다면 입력에서 더이상의 읽을 수 있는 데이터가 존재하지 않을 때 반복문을 종료하라는 것이다.

 

 

즉, 입력 스트림이 더이상 읽을 것이 없는 파일의 끝에 도달했을 때를 처리해야한다는 것이다.

 

여기서 많은 분들이 착각하는 것이 파일의 끝까지 읽었다고 EOF가 되는 것이 아니다. 끝까지 읽고난 뒤 그 다음 파일을 읽으려 할 때 읽을 데이터가 없을 때 EOF가 되는 것이다. (시점을 정확히 파악해야한다.)

abcd<EOF>

만약 위 텍스트를 읽는다면 다음과 같다.

즉, 단순히 d까지 읽었다고 EOF가 되는 것이 아니라 끝에 도달 한 후 더 읽으려고 할 때 EOF가 된다고 보시면 될 것이다.

 

참고로 에디터에서는 입력 파일을 따로 생성하여 읽지 않는 한 일반적인 키보드에서는 EOF키가 없어 EOF(입력 끝) 상태를 전송할 수가 없다. 그 대신 키맵이 따로 있는데, 콘솔에서 윈도우의 경우 CTRL + Z를 입력해주면 되며 리눅스(유닉스) 계열은 CTRL + D를 눌러주면 된다.

 

  •  cin

가장 많이 틀리는 부분이다. cin도 마찬가지로 EOF를 발생시키는데, 크게 두 가지 방식이 있다.

일단 eof() 함수를 쓰는 경우다. 마찬가지로 eof() 함수도 파일의 끝에 도달한 뒤 읽고자 할 경우 true를 반환한다.

 

아래와 같이 작성해야된다.

while(!(cin >> a >> b).eof()) 
{
	...
}

 

아래와 같이 작성하면 틀림

while(!cin.eof()) 
{
	...
}

앞서 abcd 로 예시로 들었지만, d까지 읽는다고 EOF 상태인 것이 아니다.

 

예시)

a
b
c
d

위와같이 되어 결과적으로 abcdd 출력이 되어버린다.

 

cin에서 EOF가 되면 더이상 내부 스트림 상태를 fail로 두고 val 변수에 값을 저장하지 않는다. 즉, val의 상태는 이전 루프의 값을 갖고있게 되는 것이다.

즉, eof() 가 우리가 원하는 올바른 시점에 true가 되려면 "읽기 시도를 한 후"에 eof 검사를 해야한다는 것이다.

그렇기 때문에 (cin >> a >> b).eof() 방식으로 괄호 안의 cin >> a >> b를 통해 읽은 후 eof상태인지를 검사하는 것이다.

 

eof() 함수를 써도 되지만, 더욱 간단한 방식도 있다.

while(cin >> a >> b) 
{
	...
}

보통은 cin >> a >> b 를 읽은 후 스트림 객체가 반환되지만,  위처럼 조건문 안에 있는 경우 연산자 오버로딩에 의해 bool 값으로 true 혹은 false값을 반환한다. (스트림이 정상 상태면 true, 아닐 경우 false)

 

연산자 정의는 다음과 같은 형식으로 구현되어있다.(버전마다 조금씩 상이할 수 있음)

explicit operator bool() const;

그래서 cin >> a >> b 과정에서 읽기를 실패했을 경우 스트림 상태를 변경하고, 위 연산자 오버로딩에 의해 반환되는 값이 true에서 false로 바뀌면서 while문을 종료하게 되는 것이다.

 

(사실 어떻게 bool로 캐스팅이 되는지, flag변수는 무엇인지를 설명하고 싶어도 자세히 파고들어가면 정말 복잡하다.. 설명이 너무 길어져 문제를 푸는게 아닌 사실상 스트림에 대한 개념으로 흘러가기 때문에 일단 이정도만 알아두어도 크게 문제는 없을 것이다.)

 

결과적으로 "읽은 뒤 EOF 체크"를 해야 한다는 점이 바로 포인트다.

 

 

풀이

#include <iostream>
using namespace std;

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    int a, b;
    
    while (cin >> a >> b)
    {
        cout << a + b << "\n";
    }

    return 0;
}
#include <iostream>
using namespace std;

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    int a, b;
    
    while (!(cin >> a >> b).eof())
    {
        cout << a + b << "\n";
    }

    return 0;
}

'백준' 카테고리의 다른 글

백준 10807 C++  (0) 2024.07.18
[백준 C++] 1271번 엄청난 부자2  (1) 2024.01.04
[C++ 백준] 15552번 빠른 A+B  (1) 2023.12.20
[백준 C++] 2480번 주사위  (0) 2023.12.20
[C++ 백준] 2525번 오븐 시계  (0) 2023.12.20