1

fscanf次のようにC++で使用しています:

これが私のテキストファイルです:

abcd
efgh

「efgh」の後にスペースや改行はありません。ここに私のループがあります:

FILE* fp;
char eof = 0;
do
{
    char str[20];
    fscanf(fp, "%s", str);
    std::cout<<str<<std::endl;
}
while((eof = fgetc(fp)) != eof)

The output i expect is:

abcd
efgh

But the actual output i get is:

abcd
efgh
efgh

I debugged a found that after reading "efgh" the value read into eof is '\n' and not EOF. The environment is linux mint.I want to know why always the last string is read 2 times.Please advice

4

3 に答える 3

2

最後の文字列が 2 回読み取られていません。問題は、続行するためのループのテストです。

(eof = fgetc(fp)) != eof

fgetc()これはの戻り値を に代入eofし、それが と等しくないことを確認しeofます。論理的に行うのが難しいこと。ただし、fgetc()ファイルが にあるときに を呼び出すと、 がEOF返されます-1charこれは代入のために a にキャストされますが、括弧内の部分式は値を保持します-1(型昇格規則のため)。-1255 または -127 (char が符号付きか符号なしかによる)と比較すると、最終的にループが終了します。

ループの 3 回目はfscanf()失敗し、更新されませんstr。これが、同じ値が 2 回読み取られたように見える理由です。

それを修正するための最も簡単な方法は次のとおりです。

do {
 ...
} while (!feof (fp));

ただし、多くのオペレーティング システムでは、エラーが発生するまでエンド オブ ファイル表示が確実に設定されないため、feof()ではうまく機能しません。より信頼性が高く、O/S 耐性のある手法は、使用することですfscanf()fscanf()

do {
    int result = fscanf (fp, ...whatever...);
    if (result < 0)   // end of file or i/o error?
         break;
} while (!feof (fp));
于 2012-10-11T05:36:22.823 に答える
1

[Following up on the comments of Christian Rau in another thread, I've changed my first point to correspond to what I now realize]

There are several problems with your code. Some of the most obvious are:

  • The condition at the end of your do...while has undefined behavior. In the expression eof = fgetc(fp)) != eof, you modify an object (eof), and you access it elsewhere in the expression other than to determine the value to be stored. As far as the standard is concerned, anything may happen, and in fact, different compilers will do different things.

  • You are assigning the results of fgetc to a char, rather than to an int. The return value of fgetc is either in the range [0...UCHAR_MAX] or is EOF (which is guaranteed to be negative). In other words, it can take on one more value than will fit in a char. The results of then comparing the char with EOF depend on whether plain char is signed or not. If it's not signed, it can never have a negative value, and thus, will never be equal to EOF. If it's signed, then on particular character code (0xFF, or 'ÿ' in latin-1) will be detected as end of file. The return value of fgetc should always be assigned to an int, and the conversion to char should only be done after the test for EOF.

  • You're using the results of fscanf without checking that the function has succeeded. In C++, IO, be it iostream or FILE* is not predictive. Because of the way the interface is defined, it is impossible to tell in advance whether you will encounter end of file. You must try to read, and then test whether the read succeeded.

  • You're using fscanf into a char[] without limiting the input length. This is a buffer overflow waiting to happen.

In C++, the most natural way fo writing what you're doing would be:

std::string word;
while ( anIStream >> word ) {
    //  ...
}

Using the older, C compatible streams, you would write:

char word[20];
while ( fscanf( fp, "%19s", word ) == 1 ) {
    //  ...
}

In both cases, the check for success controls the loop; in the case of the C interface, you use a format width specifier to ensure that you don't overrun the buffer. (And in both cases, you must define the variables being read outside the loop, even though you will only use them in the loop.)

于 2012-10-11T07:36:10.147 に答える
0

あなたはeofでeofをチェックしています。このように確認してみてください

while( (eof = fgetc(fp)) != EOF)
于 2012-10-11T05:36:19.763 に答える