문제

다음과 같은 C++ 코드는 ifstream 텍스트 파일(한 줄에 하나의 숫자가 있음)에서 정수가 나올 때까지 정수를 읽는 객체 EOF.마지막 줄의 정수를 두 번 읽는 이유는 무엇입니까?이 문제를 해결하는 방법은 무엇입니까?

암호:

#include <iostream>
#include <fstream>
using namespace std;

int main()
{
    ifstream iFile("input.txt");    // input.txt has integers, one per line

    while (!iFile.eof())
    {
        int x;
        iFile >> x;
        cerr << x << endl;
    }

    return 0;
}

입력.txt:

10  
20  
30

산출:

10  
20  
30  
30

메모:코드 조각을 작게 유지하기 위해 모든 오류 검사 코드를 건너뛰었습니다.위의 동작은 Windows(Visual C++), cygwin(gcc) 및 Linux(gcc)에서 나타납니다.

도움이 되었습니까?

해결책

일련의 사건을 면밀히 따르십시오.

  • 10개를 잡아라
  • 20개를 잡아라
  • 30개를 잡아라
  • EOF 확보

마지막에서 두 번째 반복을 살펴보세요.30개를 확보한 다음 계속해서 EOF를 확인했습니다.EOF 마크가 아직 읽히지 않았기 때문에 EOF에 도달하지 못한 것입니다("이진적으로" 말하면 개념적 위치는 30 라인 바로 뒤에 있습니다).따라서 다음 반복을 계속합니다.x는 이전 반복에서 여전히 30입니다.이제 스트림에서 읽고 EOF를 얻습니다.x는 30으로 유지되고 ios::eofbit가 증가합니다.stderr x(이전 반복에서와 마찬가지로 30)로 출력합니다.다음으로 루프 조건에서 EOF를 확인하면 이번에는 루프에서 벗어납니다.

이 시도:

while (true) {
    int x;
    iFile >> x;
    if( iFile.eof() ) break;
    cerr << x << endl;
}

그런데 코드에 또 다른 버그가 있습니다.빈 파일에서 실행해 본 적이 있나요?당신이 얻는 행동은 똑같은 이유입니다.

다른 팁

나는 이 예제를 좋아하는데, 지금은 while 블록 내부에 추가할 수 있는 검사를 생략합니다.

ifstream iFile("input.txt");        // input.txt has integers, one per line
int x;

while (iFile >> x) 
{
    cerr << x << endl;
}

얼마나 안전한지는 잘 모르겠습니다...

이에 대한 대체 접근 방식이 있습니다.

#include <iterator>
#include <algorithm>

// ...

    copy(istream_iterator<int>(iFile), istream_iterator<int>(),
         ostream_iterator<int>(cerr, "\n"));

EOF 패턴은 EOF 검사 프로세스를 '부트스트랩'하기 위해 프라임 읽기가 필요합니다.빈 파일은 처음 읽을 때까지 처음에 EOF가 설정되지 않는다는 점을 고려하세요.프라임 읽기는 이 인스턴스에서 EOF를 포착하고 루프를 완전히 건너뜁니다.

여기서 기억해야 할 것은 파일의 사용 가능한 데이터를 지나 처음으로 읽으려고 시도할 때까지 EOF를 얻지 못한다는 것입니다.정확한 양의 데이터를 읽으면 EOF에 플래그가 지정되지 않습니다.

파일이 비어 있으면 EOF가 루프에 들어갈 때 값이 x로 설정되는 것을 방지하므로 주어진 코드가 인쇄되었을 것임을 지적해야 합니다.

  • 0

따라서 프라임 읽기를 추가하고 루프의 읽기를 끝으로 이동하십시오.

int x;

iFile >> x; // prime read here
while (!iFile.eof()) {
    cerr << x << endl;
    iFile >> x;
}

원본 코드를 많이 수정하지 않으면 다음과 같이 될 수 있습니다.

while (!iFile.eof())
{  
    int x;
    iFile >> x;
    if (!iFile.eof()) break;
    cerr << x << endl;
}

그러나 나는 일반적으로 위의 두 가지 다른 솔루션을 선호합니다.

int x;
ifile >> x

while (!iFile.eof())
{  
    cerr << x << endl;        
    iFile >> x;      
}

마지막 줄 끝에는 >> 연산자로 읽을 수 없고 파일 끝이 아닌 새 줄 문자가 있습니다.실험을 해보고 새 줄(파일의 마지막 문자)을 삭제하십시오. 중복이 발생하지 않습니다.유연한 코드를 갖고 원치 않는 효과를 피하려면 다른 사용자가 제공한 솔루션을 적용하면 됩니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top