|
使用feof()控制读取循环有什么问题?' @6 e. Q1 I4 U' @4 N& a/ y4 T: ]
#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;}
( R: S) c% H4 s9 `: `7 ?& | 这个循环有什么问题?% |4 Q4 z1 n( X1 c5 v \* [
, w- s' I. c$ W' O+ O% b' w
解决方案:
7 @ K( S# v( h& _ V% c9 } TL;DRwhile(!feof)这是错误的,因为它测试了一些你需要知道的无关紧要的测试你需要知道的东西。因此,你错误地执行了假设它正在访问成功读取的数据的代码,这从未发生过。
# Q: P& `8 `1 T! F+ m$ R( q; I我想提供一个抽象的、高层次的观点。所以,如果你对的话while(!feof)对实际操作感兴趣,请继续阅读。
Y) L6 f: ^4 E( i1 ^并发性和同时性I/O 操作与环境互动。环境不是你程序的一部分,也不受你的控制。环境真的与你的程序同时存在。与所有并发事件一样,当前状态的问题毫无意义:并发事件之间没有同时的概念。状态的许多属性根本不同时存在存在。
, T5 Y' r( W' C7 I: S; o/ {假设你想问,你有更多的数据吗?。您可以询问并发容器或您的 I/O 系统。但答案通常是不可操作的,所以毫无意义。那么,如果容器说是怎么办——当你试图阅读时,它可能不再有数据。同样,如果答案是否,当你试图阅读时,数据可能已经到达。结论是,有没有像我有数据这样的属性,因为你不能对任何可能的答案采取有意义的行动。(缓冲输入稍微好一点,你可能会得到一个是的,我有数据来保证,但你仍然必须能够处理相反的情况。输出必须和我描述的一样糟糕:你永远不知道磁盘或网络缓冲区是否已满。3 Y" Y- x! t6 N9 G; W \
因此,我们得出结论,询问 I/O 系统是否能够执行 I/O 操作是不可能的,其实也是不合理的。唯一可能与之互动的方法(就像并发容器一样)是尝试操作并检查它是成功还是失败。在你与环境互动的那一刻,只有在那一刻,你才能知道互动是否实际上是可能的。此时,您必须承诺果你愿意,这是一个同步点。
2 {, p6 }, ~* ?( aEOF现在我们到了EOF。EOF 是您从尝试的I/O 操作中获得的响应。这意味着你正在尝试阅读或写一些内容,但你不能读取或写任何数据,而是在输入或输出的结尾。基本上所有的 I/O API 都是这样,不管是 C 标准库、C iostream 还是其他库。I/O 操作成功,你是根本无法知道未来的操作会成功吗?必须在响应成功或失败之前,先尝试操作。
; Z6 a# \* W6 q例子请注意每个例子,我们首先尝试 I/O 操作,然后当结果有效时使用结果。进一步注意总是必须使用 I/O 操作结果,尽管在每个示例中使用不同的形状和形式。
) U1 G* W, \. _2 [ `C stdio,读取文件:c for(;(;){ size_t n = fread(buf,1,bufsize,infile); consume(buf,n); if (n == 0) { break; }
- B* x9 r8 c" q6 [5 F! l" H# u我们必须使用的结果是n,读取的元素数量(可能少于零)。
) \' o' `; ^) e9 k; M$ }C标准输入法,scanf:c for (int a,b,c; scanf("%d %d %d",&a,&b,&c) == 3. ) { consume(a,b,c); }
3 g+ c# B. M- ?, e结果是 的返回值scanf,即转换元素数。
: v' ~1 y$ x0 Q2 e. _C 、iostreams 格式化提取:c for (int n; std::cin >> n; ) { consume(n); }3 ]# @8 T0 p: B7 ~5 [% `
我们必须使用的结果是std::cin它本身可以在布尔的上下文中进行评估,并告诉我们流动是否仍然存在good()状态。$ X" i1 b4 C- M3 `
C ,iostreams getline:c for (std::string line; std::getline(std::cin,line); ()()()()()consume(line); }
% W6 y( w6 g+ e3 r/ @1 f. |我们必须再次使用它std::cin,就像以前一样。
) P- t2 ]7 P% {. X. j8 \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 */ }
) j4 X `8 w) U1 J9 w2 \, g+ J U我们在这里使用的结果是k,字节数。这里的重点是,我们只能知道写入操作后写了多少字节。: k5 K, W1 U. g7 V
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);, ?: C) K' w- M
我们必须使用的结果是nbytes,直到包含换行符的字节数(如果文件没有以换行符结束,则为 EOF)。
/ v, {# g9 P# L+ H2 A; s* f3 v$ F2 g请注意,-发生错误或到达 EOF 函数显式返回(而不是 EOF!)。" q4 _0 O7 d# Q' {( L6 l: o
你可能会注意到,我们很少拼出实际的单词EOF。我们通常以其他我们更感兴趣的方式检测错误的条件(例如,我们不能尽可能多地执行我们想要的 I/O)。每个示例中都有一些 API 功能可以明确地告诉我们遇到了 EOF 状态,但这不是一个非常有用的信息。它比我们经常关心的细节要多得多。I/O 是否成功,而不是如何失败。
! D6 s! z( b9 l: C7 A实际查询 EOF 状态的最后一个例子:假设你有一个字符串,并且想测试它是否代表一个整数,除了空间,没有额外的位置。C iostreams,这样:```c3 q) T8 B6 h! a4 M; B, g% M
std::string input = ” 123 “; // example6 s8 I# G6 t( A& u2 M7 f
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}```1 F6 V. K$ ^. u! R& J4 G" N P( _
我们在这里使用两个结果。iss检查流对象本身是否以格式提取value成功。然而,在消耗空间后,我们实施了另一个 I/O/ 操作,iss.get()并期待它作为 EOF 失败,如果整个字符串被格式化提取消耗,就会发生这种情况。
8 w9 V; D* _' \6 v1 C1 E9 b在 C 标准库中,您可以strto*l检查指针是否已到达输入字符串的末尾,以实现与函数相似的功能。 |
|