상세 컨텐츠

본문 제목

백준 class1)10951번 A+B-4

백준 연습

by 빙하둘리 2022. 8. 10. 22:21

본문

728x90

백준 10951번 A+B-4

https://www.acmicpc.net/problem/10951

 

10951번: A+B - 4

두 정수 A와 B를 입력받은 다음, A+B를 출력하는 프로그램을 작성하시오.

www.acmicpc.net

처음 나의 사고 과정) 처음에는 A를 저장하는 배열, B를 저장하는 배열 각각 따로 동적할당해서 같은 인덱스에 있는 요소끼리 더하는 방법을 생각했다. 길이가 어떻게 될지(언제 값 받는 것을 종료할지) 모르는 상황에서 동적배열은 임의의 숫자로 해야 되나... 고민도 많이 됐었다.

또는 while문 break문 continue문 섞어서 쓰면서 A가 엔터값을 받고 엔터를 누르면 종료하겠지 하면서 프로그램을 짰는데 그게 아니었다.

 

EOF 개념을 사용하는 게 관건이었는데...

EOF란 End Of File의 약자로서, 파일의 끝을 표현하기 위해서 정의해 놓은 상수이다.

EOF의 값은 -1로 정의되었다.

EOF를 반환하는 시기는 대표적으로 다음 두 경우가 있다.

1. 함수 호출의 실패

2. Windows에서 CTRL+Z 키, Linux에서 CTRL+D 키가 입력되는 경우

그러므로 10951번 문제는 CTRL+Z 키를 눌러서 파일의 끝인 EOF을 반환하고, 더하기 값을 출력해야 된다.

 

C언어에서 EOF 사용 예시)

fgetc 함수는 #include <stdio.h>라는 헤더파일에 있는 원형이 int fgetc(FILE * stream);인 함수며, 문자 입력 함수다.

#include <stdio.h>

int main(void) {
	int ch;
    
    while(1)
    {
    	ch = getchar();
    	if(ch==EOF)
        	break;
        putchar(ch);
    }
    return 0;
}

 

EOF가 파일의 끝을 나타내고 -1의 값을 가지고 있는 상수라는 점을 이용해서 코드를 작성해보자.

일단 크게 두가지 방법을 소개한다.

 

1.scanf와 EOF의 상수 값 사용하기

stdio.h(혹은 cstdio)의 scanf의 경우는 int반환값이 존재한다. 반환값은 읽어들인 데이터의 개수를 반환한다.

ex) scanf("%d %d %d, &a, &b, &c); 라고 했을 떄 지정한 포맷("%d")에 따른 3개의 변수에 알맞게 입력이 들어왔으면 3을 반환한다.

 

만약 데이터를 읽는동안 파일의 끝(EOF)에 도달한 뒤 읽고자 하면 -1 을 반환한다. 즉 다음과 같이 작성할 수 있다.

while(scanf("%d %d", &a, &b) != -1) {
	...
}

단, 헤더파일 stdio.h에 있는 scanf 함수를 쓰면

iostream의 함수 cin, cout과 시간 단축용으로 쓰이는 ios::sync_with_stdio(false);와 cin.tie(null);을 쓸 수 없다.

 

2.cin과 EOF 사용

cin도 마찬가지로 EOF를 발생시킨다.

따라서 eof() 함수를 써본다. 마찬가지로 eof() 함수도 파일의 끝에 도달한 뒤 읽고자 할 경우 true를 반환한다.

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

cin으로 a,b를 받던 과정에서 eof에 도달하면 -1을 반환하게 되여 while 조건문은 false가 되므로 반복문을 나가게 된다.

 

그런데 다음과 같이 작성하면 틀리게 된다.

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

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

 

예로들어 다음과 같이 입출력을 받는다고 해보자.

char val;
while(!cin.eof()) {
	cin >> val;
	cout << val;
}

그리고 입력으로 다음과 같이 입력한다고 가정해보자.

a
b
c
d

그러면 위 출력은 어떻게 될까?

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

 

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

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

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

 

3. 더욱 간단한 방식-조건문 안에 있는 경우 연산자 오버로딩에 의해서 bool 값 반환

예시 코드

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

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

(C++ 연산자 오버로딩과 스트림에 대해서 강의 보기)

 

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

explicit operator bool() const;

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

 

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

 

 

결과적으로 cin을 통한 방식과 scanf 방식 모두 "읽은 뒤 EOF 체크"를 해야 한다는 점이 바로 포인트다.

 

풀이

방법1 scanf

#include <cstdio>
 
int main(int argc, const char * argv[]) {
 
	int a, b;
 
	// 또는 scanf("%d %d", &a, &b) == 2 로도 가능
	while(scanf("%d %d", &a, &b) != -1) {
		printf("%d\n", a + b);
	}
 
	return 0;
}

 

방법2 cin.eof()

c++ 표준 입력 방식인 cin 을 사용하여 eof() 함수를 활용하는 방식이다. 앞서 설명에서 말했듯, 반드시 EOF 시점이 언제인지를 판단하고 짜야한다.

#include <iostream>
using namespace std;
 
int main(int argc, const char *argv[]) {
 
	int a, b;
	while (!(cin >> a >> b).eof()) {	// 혹은 eof() 대신 fail()을 사용해도 된다.
		cout << a + b << "\n";
	}
 
	return 0;
}

 

방법3 cin operator bool

cin이 조건식에 있으면 bool 값이 반환되도록 오버로딩 된 방식을 활용한 것이다.

#include <iostream>
using namespace std;
 
int main(int argc, const char *argv[]) {
 
	int a, b;
	while (cin >> a >> b) {
		cout << a + b << "\n";
	}
 
	return 0;
}

 

방법 4. 향상 된 입출력 + cin operator bool

방법3에다가 향상된 입출력을 위해서 ios_base::sync_with_stdio(false); cin.tie(NULL);을 써준다.

#include <iostream>
using namespace std;
 
int main(int argc, const char *argv[]) {
 
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
 
	int a, b;
	while (cin >> a >> b) {
		cout << a + b << "\n";
	}
 
	return 0;
}

 

 

참고자료1)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

참고자료2)  ios::sync_with_stdio(false);와 cin.tie(null);에 관하여

https://dingcoding.tistory.com/m/62

728x90

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

10951, 10952  (0) 2022.08.12
백준 class1) 11720번 숫자의 합  (0) 2022.08.11
백준 class1)1008번 A/B  (0) 2022.08.10
백준 10951번 A+B-4 오답  (0) 2022.08.10
백준 2475번 검증수  (0) 2022.08.10

관련글 더보기

댓글 영역