(초록색 글자 클릭 시 문제로 이동)
두 정수 A와 B를 입력받은 다음, A+B를 출력하는 프로그램을 작성하시오. (테스트케이스 X)
10952번 A+B-5번과 마찬가지로 테스트케이스가 없다. 즉, 반복하는 횟수를 모르기 때문에 for
문이 아니라 while
문을 사용해야 한다.
for문 : 반복 횟수를 정확히 알 때
while문 : 반복 조건을 설정할 때
그러나 10952번과 다른 점은, A와 B가 0일 때 종료되는 것이 아니라 입력되는대로 계속 반복된다는 것이다.
조건을 어떻게 설정해야 할 것인가에 대해서 방향성을 잃었다.
1번째 시도 : 문제에 나와있는 0 < A, B < 10
을 조건으로 사용했다.
➡ 결과 : 🚨"출력초과"🚨
2번째 시도 : 조건을 '입력'받는 것으로 변경 (다른 블로그의 답안을 참고)
➡ 결과 : ✨정상 작동!
➡ EOF
에 대한 개념 보충 필요
3번째 시도 : 2번째 시도에서 향상된 입출력 추가
➡ 최종 답안 제출
자세한 코드는 아래에서 설명하겠다!
위에서 설명한 것처럼 while문의 조건을 어떻게 설정해야 할 지 헷갈렸다. EOF(End Of File)의 개념이 없으니 그럴 수 밖에..
그래서 0 < A, B < 10
을 조건으로 봤다. while문 조건에 긴 식을 입력하면 오류가 낫기에, while(true)로 무한루프를 돌게 만들었고, 그 안에 if문을 이용하여 조건을 걸어 빠져나오게 했다.
결론적으로 오답이었지만 코드는 다음과 같다.
#include <iostream>
using namespace std;
int main()
{
int a, b;
while (true) {
cin >> a >> b;
if (a >= 10 || b >= 10) {
break;
}
else if (a < 0 || b < 0) {
break;
}
else {
cout << a + b << "\n";
}
}
return 0;
}
출력초과 : 하나만 출력하면 되는 문제에서 출력 후 종료하지 않았을 경우.
'틀렸습니다'와 같은 의미. 너무 많은 출력을 하는 경우에 발생한다. 무한 루프에 빠진 경우, 무한 루프에서 출력을 한다면 출력초과를 받을 수 있다고 한다.
(자세한 설명은 링크 참조 : 자주 틀리는 이유 stackdotnews)
이건 내가 프로그램으로 따로 돌렸을 때도, 무한루프에 빠졌다. 즉 오답이라는 소리다. 무한루프에 빠지지 않게 하려면 어떻게 답을 수정해야 하는 걸까?
언제까지 입력되는지 모른다. 간단하게 생각하면 입력이 되면, 더하는 것이다. 입력 되지 않으면 반복될 필요도 없다. 따라서 while문의 () 안에는 입력문이 들어가면 된다.
while (cin >> a >> b) {
...
}
이렇게 말이다. 입력이 있을 경우는 true, 없을 경우는 false를 리턴하게 되어 테스트 케이스가 없어도 문제를 해결할 수 있다.
코드는 다음과 같다. 이 문제에서는 EOF(End Of File)
의 개념이 사용되었다고 한다. 이에 대한 자세한 설명은 다른 블로그의 글을 통해 요약하여 코드 아래에 보충하였다.
#include <iostream>
using namespace std;
int main()
{
int a, b;
while (cin >> a >> b) {
cout << a + b << "\n";
}
return 0;
}
▶EOF(End Of File)
주어진 입력 파일만 갖고 입력을 받을 때 더이상 읽을 수 있는 데이터가 없는 경우. 파일의 끝
위 문제는 입력에서 더이상 읽을 수 있는 데이터가 존재하지 않을 때 반복문을 종료한다. 즉, EOF 개념이라는 것.
이때 파일의 끝까지 읽었다고 EOF가 되는 것은 아님. 끝까지 읽고 난 뒤 그 다음 파일을 읽으려 할 때, 읽을 데이터가 없을 때 EOF가 되는 것이다.
예를 들어 1 2 3 4 <EOF>
가 있을 때,
Read | Status |
---|---|
1 | True |
2 | True |
3 | True |
4 | True |
<EOF> | False |
단순히 4까지 읽었다고 EOF가 아니라 끝에 도달해서 하나 더 읽으려고 할 때 EOF가 된다.
stdio.h의 scanf는 int반환값이 있다.
만약 데이터를 읽는 동안 파일의 끝(EOF)에 도달한 뒤 읽고자 하면 -1을 반환한다.
다음과 같이 작성할 수 있다.
while (scanf("%d %d", &a, &b) != -1) {
...
}
가장 많이 틀리는 부분이라고 한다. cin 도 마찬가지로 EOF를 발생시킨다.
1번째 방식은 eof() 함수
를 쓰는 경우이고,
2번째 방식은 간단히 출력
하는 경우이다.
1번째 방식은 scanf와 마찬가지로 eof()
함수도 파일의 끝에 도달한 뒤 읽고자 할 경우 true를 반환한다. 이때 eof()
가 올바른 시점에 true가 되려면 "읽기 시도를 한 후"에 eof검사를 해야 한다.
//cin >> a >> b로 읽기 시도를 한 후
// .eof()로 eof검사
while(!(cin >> a >> b).eof()) {
...
}
while( cin >> a >> b) {
...
}
보통은 cin >> a >> b
를 읽은 후 스트림 객체가 반환된다. 그러나 위처럼 조건문 안에 있는 경우엔 연산자 오버로딩으로 true 혹은 false 값을 반환한다.
따라서 cin >> a >> b
과정에서 읽기를 실패했을 경우, 스트림 상태를 변경하고, 위 연산자 오버로딩에 의해 반환된 값이 true에서 false로 바뀌면서 while문을 종료하게 된다.
🌟포인트🌟 : cin, scanf 방식 모두 "읽은 뒤 EOF 체크!"를 해야 한다.
2-2번에서 입출력 동기화를 끊어주는 방법을 합쳐서 작성하였다.
🚨 참고 🚨
그냥 풀이 할 수 있지만,C와 C++의 표준 입출력 동기화를 끊어주는 방법으로 진행하였다. 이번 문제에서는 입력과 출력이 번갈아 반복되므로cin.tie(NULL)
도 함께 써준다.
자세한 설명은 15552번 풀이에 나와있다. (15552에 대한 설명 바로가기)
#include <iostream>
using namespace std;
int main()
{
cin.tie(NULL); //입출력 끊기
ios_base::sync_with_stdio(false); //동기화 해제
int a, b;
// cin >> a >> b 로 읽기 시도
// true일 때 while문 반복. false일 때 while문 종료
//즉, 입력이 있을 시엔 while문을 계속 반복하게 될 것이고, 입력이 없을 시 반복 종료.
while (cin >> a >> b) {
cout << a + b << "\n";
}
return 0;
}
순서대로
제출번호 40872592 : 3번째 시도(향상된 입출력 추가) ➡ 0ms
제출번호 40872461 : 2번째 시도(EOF
사용) ➡ 4ms
제출번호 40871940 : 1번째 시도(while(true)
사용) ➡ 출력초과
EOF 개념을 보고 나니까 내가 아직 모르는게 너무 많은 것 같다. 더더 겸손해져야 할 것 같다.
이해하고 내 걸로 다듬는데에 시간이 좀 걸렸다. 내 벨로그에 있는 다수의 글에는 Stranger's LAB님의 티스토리에서 참고한 게 많다. 이 분 덕분에 혼자 공부해도 나아가는 것 같다..!!
임시저장 해놨던 거 다 날라갔다... 시간이 한참 지난 지금 기억이 가물가물하지만 다시 적는다.
임시저장 해놨던 것도, 시간이 한참 지나 적은 거였다. 그래서인지 그때 내가 뭘 느꼈는지, 어떻게 크게 다가왔는지 가물하다. 최대한 많은 문제를 풀려고 하는 것도 좋지만 '질' 에 더 신경 써야 겠다고 생각이 들었다. 문제를 풀고 휙 넘어갈 게 아니라 벨로그 글까지 다 쓰고 나서 넘어가야겠다고 반성했다.