回答

收藏

为什么“while (!feof (file))”总是错的?

技术问答 技术问答 407 人阅读 | 0 人回复 | 2023-09-12

使用feof()控制读取循环有什么问题?
4 O: y' e* }9 {; i0 }8 i6 R" b
    #include #include intmain(int argc,char **argv){    char *path = "stdin";    FILE *fp = argc > 1 ? fopen(path=argv[1],"r") : stdin;    if( fp == NULL()()()()()()()())()()()())()()())())()())())())())()())()))())()()))())()))())())()))()())())()()))()())()()))()()())())()()())())()))()())()))()()))()()))()())))()()()()))()()()))()()))()()()()()())()))())()))())()()()())()()()()))()())())())()())())()()())()()))()()()()))()())()()()()()()())()()))())()()()())())))()))()()())))()()()))())))()())()))()()())()()()()()()()()()())())()()())()())())))()))))())))()()()))))))())()()()()()()()()()()()()()()()()()()()()()()()()()()()()))())))))())())))))()))))))()))()))())()()()()()()()()()()()()))))()()()()()()()()()()))()()()()()()()()()()()()()()()perror(path);        return EXIT_FAILURE;   }    while( !feof(fp){ )( )( )* THIS IS WRONG *        /    * Read and process data from file… */   }    if( fclose(fp) != 0()()()()()()()())()()()())()()())())()())())())())()())()))())()()))())()))())())()))()())())()()))()())()()))()()())())()()())())()))()())()))()()))()()))()())))()()()()))()()()))()()))()()()()()())()))())()))())()()()())()()()()))()())())())()())())()()())()()))()()()()))()())()()()()()()())()()))())()()()())())))()))()()())))()()()))())))()())()))()()())()()()()()()()()()())())()()())()())())))()))))())))()()()))))))())()()()()()()()()()()()()()()()()()()()()()()()()()()()()))())))))())())))))()))))))()))()))())()()()()()()()()()()()()))))()()()()()()()()()()))()()()()()()()()()()()()()()()perror(path);        return EXIT_FAILURE;   }    return EXIT_SUCCESS;}
    % A) x: C$ K: m
这个循环有什么问题?
" ^1 T8 U& x6 R4 L; j                                                               
* X: `/ V' _  L7 J  Q* l9 c    解决方案:                                                               
4 M0 y# O2 f; t& Y/ k/ R                                                                TL;DRwhile(!feof)这是错误的,因为它测试了一些你需要知道的无关紧要的测试你需要知道的东西。因此,你错误地执行了假设它正在访问成功读取的数据的代码,这从未发生过。, z  {9 N0 l# M
我想提供一个抽象的、高层次的观点。所以,如果你对的话while(!feof)对实际操作感兴趣,请继续阅读。. @, v8 k# U2 `- J+ d
并发性和同时性I/O 操作与环境互动。环境不是你程序的一部分,也不受你的控制。环境真的与你的程序同时存在。与所有并发事件一样,当前状态的问题毫无意义:并发事件之间没有同时的概念。状态的许多属性根本不同时存在存在。
: r! e% g! v* G: X0 K( J假设你想问,你有更多的数据吗?。您可以询问并发容器或您的 I/O 系统。但答案通常是不可操作的,所以毫无意义。那么,如果容器说是怎么办——当你试图阅读时,它可能不再有数据。同样,如果答案是否,当你试图阅读时,数据可能已经到达。结论是,有没有像我有数据这样的属性,因为你不能对任何可能的答案采取有意义的行动。(缓冲输入稍微好一点,你可能会得到一个是的,我有数据来保证,但你仍然必须能够处理相反的情况。输出必须和我描述的一样糟糕:你永远不知道磁盘或网络缓冲区是否已满。
# g& _0 r' O2 A, b6 F1 O- t因此,我们得出结论,询问 I/O 系统是否能够执行 I/O 操作是不可能的,其实也是不合理的。唯一可能与之互动的方法(就像并发容器一样)是尝试操作并检查它是成功还是失败。在你与环境互动的那一刻,只有在那一刻,你才能知道互动是否实际上是可能的。此时,您必须承诺果你愿意,这是一个同步点。
' T2 g* M, Z% iEOF现在我们到了EOF。EOF 是您从尝试的I/O 操作中获得的响应。这意味着你正在尝试阅读或写一些内容,但你不能读取或写任何数据,而是在输入或输出的结尾。基本上所有的 I/O API 都是这样,不管是 C 标准库、C   iostream 还是其他库。I/O 操作成功,你是根本无法知道未来的操作会成功吗?必须在响应成功或失败之前,先尝试操作。0 `% E9 C# g  i6 p
例子请注意每个例子,我们首先尝试 I/O 操作,然后当结果有效时使用结果。进一步注意总是必须使用 I/O 操作结果,尽管在每个示例中使用不同的形状和形式。
8 H( C. x3 i" O& ~) X. S# O* VC stdio,读取文件:c    for(;(;){     size_t n = fread(buf,1,bufsize,infile);        consume(buf,n);        if (n == 0) { break;        }
" i; Y9 a; {! I* V# o我们必须使用的结果是n,读取的元素数量(可能少于零)。; i, _% L& C# a+ ]8 ]
C标准输入法,scanf:c    for (int a,b,c; scanf("%d %d %d",&a,&b,&c) == 3. ) {       consume(a,b,c);    }" J! [* a7 B8 Q! n+ i6 m( d
结果是 的返回值scanf,即转换元素数。$ Q5 d( K) {* d) \/ N3 t/ d
C  、iostreams 格式化提取:c    for (int n; std::cin >> n; ) {        consume(n);    }
  i7 k. Y+ n2 n. Y我们必须使用的结果是std::cin它本身可以在布尔的上下文中进行评估,并告诉我们流动是否仍然存在good()状态。6 w! J; d: r$ {. M" s2 [- J0 w& G
C   ,iostreams getline:c    for (std::string line; std::getline(std::cin,line); ()()()()()consume(line);    }
$ n: I. |0 r; s3 H, N' f  k( t& \我们必须再次使用它std::cin,就像以前一样。; C% U& n# g0 J: Q8 Y* e
POSIX,write(2)刷新缓冲区:c    char const * p = buf;    ssize_t n = bufsize;    for (ssize_t k = bufsize; (k = write(fd,p,n)) > 0; p  = k,n -= k) {}    if (n != 0* error,failed to write complete buffer */ }9 u) k# ]) M9 r. K7 ?8 D- D
我们在这里使用的结果是k,字节数。这里的重点是,我们只能知道写入操作后写了多少字节。$ X2 L# {6 N0 S
POSIX getline()c    char *buffer = NULL;    size_t bufsiz = 0;    ssize_t nbytes;    while ((nbytes = getline(&buffer,&bufsiz,fp)) != -1)              * Use nbytes of data in buffer *      free(buffer);) A" E! [% B% S; c  c4 ^
我们必须使用的结果是nbytes,直到包含换行符的字节数(如果文件没有以换行符结束,则为 EOF)。
4 c) G9 ?0 l0 S) S  ~- N) r8 @请注意,-发生错误或到达 EOF 函数显式返回(而不是 EOF!)。
( X1 C2 p( B! }你可能会注意到,我们很少拼出实际的单词EOF。我们通常以其他我们更感兴趣的方式检测错误的条件(例如,我们不能尽可能多地执行我们想要的 I/O)。每个示例中都有一些 API 功能可以明确地告诉我们遇到了 EOF 状态,但这不是一个非常有用的信息。它比我们经常关心的细节要多得多。I/O 是否成功,而不是如何失败。/ `7 k3 R7 Q$ E6 w
实际查询 EOF 状态的最后一个例子:假设你有一个字符串,并且想测试它是否代表一个整数,除了空间,没有额外的位置。C   iostreams,这样:```c/ E, u- a4 s9 m3 B: m* P
                std::string input = ”   123   “;   // example7 m8 `& ~0 Z/ u' K3 R" a
std::istringstream iss(input);int value;if (iss >> value >> std::ws && iss.get() == EOF)    consume(value);} else    // error,"input" is not parsable as an integer}```
( a- C: A3 [4 @4 t$ J3 {# p9 {我们在这里使用两个结果。iss检查流对象本身是否以格式提取value成功。然而,在消耗空间后,我们实施了另一个 I/O/ 操作,iss.get()并期待它作为 EOF 失败,如果整个字符串被格式化提取消耗,就会发生这种情况。& c- m. b3 {2 y2 S
在 C 标准库中,您可以strto*l检查指针是否已到达输入字符串的末尾,以实现与函数相似的功能。
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则