getchar() 和 EOF 总结
大 师级经 典的著作,要字斟句酌的去 读 ,去理解。以前在看 K&R 的 The C Programming Language(SecondEdition) 第 1.5 节 的字符 输 入 / 输 出,被 getchar() 和 EOF 所迷惑了。可能主要 还 是由于没有搞清楚 getchar() 的工作原理和 EOF 的用法。因此 , 感 觉 很有必要 总结 一下,不然,很多 琐 碎的知 识 点 长时间过 后就会淡忘的,只有写下来才是最好的方法。 其 实 , getchar() 最典型的程序也就几行代 码 而已。本人所用的 环 境是 DebianGNU/Linux ,在其他系 统 下也一 样 。 一、 getchar 的两点 总结 : 1.getchar是以行 为单 位 进 行存取的。 当用 getchar 进 行 输 入 时 ,如果 输 入的第一个字符 为 有效字符 ( 即 输 入是文件 结 束符 EOF , Windows 下 为组 合 键 Ctrl+Z , Unix/Linux 下 为组 合 键 Ctrl+D) ,那 么 只有当最后一个 输 入字符 为换 行符 '\n'( 也可以是文件 结 束符 EOF , EOF 将在后面 讨论 ) 时 , getchar 才会停止 执 行,整个程序将会往 下 执 行。譬如下面程序段:
while (( c = getchar ()) != EOF ){ putchar ( c ); }
执 行程序, 输 入: abc ,然后回 车 。 则 程序就会去 执 行 puchar(c) ,然后 输 出 abc , 这 个地方不要忘了,系 统输 出的 还 有一个回 车 。然后可以 继续输 入,再次遇到 换 行符的 时 候,程序又会把那一行的 输 入的字符 输 出在 终 端上。 对 于 getchar ,肯定很多初学的朋友会 问 , getchar 不是以字符 为单 位 读 取的 吗 ?那 么 ,既然我 输 入了第一个字符 a ,肯定 满 足 while 循 环 (c = getchar()) != EOF 的条件阿,那 么应该执 行 putchar(c) 在 终 端 输 出一个字符 a 。不 错 ,我在用 getchar 的 时 候也是一直 这么 想的,但是程序就偏偏不着 样执 行,而是必需 读 到一个 换 行符或者文件 结 束符 EOF 才 进 行一次 输 出。 对这 个 问题 的一个解 释 是,在大 师编 写 C 的 时 候,当 时 并没有所 谓终 端 输 入的概念,所有的 输 入 实际 上都是按照文件 进 行 读 取的,文件中一般都是以行 为单 位的。因此,只有遇到 换 行符,那 么 程序会 认为输 入 结 束,然后采取 执 行程序的其他部分。同 时 , 输 入是按照文件的方式存取的,那 么 要 结 束一个文件的 输 入就需用到 EOF (Enf Of File). 这 也就是 为 什 么 getchar 结 束 输 入退出 时 要用 EOF 的原因。 2.getchar()的返回 值 一般情况下是字符,但也可能是 负值 ,即返回 EOF 。 这 里要 强调 的一点就是, getchar 函数通常返回 终 端所 输 入的字符, 这 些字符系 统 中 对应 的 ASCII 值 都是非 负 的。因此,很多 时 候,我 们 会写 这样 的两行代 码 :
这样 就很有可能出 现问题 。因 为 getchar 函数除了返回 终 端 输 入的字符外,在遇到 Ctrl+D(Linux 下 ) 即文件 结 束符 EOF 时 , getchar () 的返回 EOF , 这 个 EOF 在函数 库 里一般定 义为 -1 。因此,在 这种 情况下, getchar 函数返回一个 负值 ,把一个 负值赋给 一个 char 型的 变 量是不正确的。 为 了能 够让 所定 义 的 变 量能 够 包含 getchar 函数返回的所有可能的 值 ,正确的定 义 方法如下 (K&R C 中特 别 提到了 这 个 问题 ) :
二、 EOF 的两点 总结 ( 主要指普通 终 端中的 EOF) 1.EOF 作 为 文件 结 束符 时 的情况: EOF虽 然是文件 结 束符,但并不是在任何情况下 输 入 Ctrl+D(Windows 下 Ctrl+Z) 都能 够实现 文件 结 束的功能,只有在下列的条件下,才作 为 文件 结 束符。 (1)遇到 getcahr 函数 执 行 时 ,要 输 入第一个字符 时 就直接 输 入 Ctrl+D ,就可以跳出 getchar(), 去 执 行程序的其他部分; (2)在前面 输 入的字符 为换 行符 时 ,接着 输 入 Ctrl+D ; (3)在前面有字符 输 入且不 为换 行符 时 ,要 连 着 输 入两次 Ctrl+D , 这时 第二次 输 入的 Ctrl+D 起到文件 结 束符的功能,至于第一次的 Ctrl+D 的作用将在下面介 绍 。 其 实 , 这 三 种 情况都可以 总结为 只有在 getchar() 提示新的一次 输 入 时 ,直接 输 入 Ctrl+D 才相当于文件 结 束符。 2.EOF作 为 行 结 束符 时 的情况, 这时 候 输 入 Ctrl+D 并不能 结 束 getchar(), 而只能引 发 getchar() 提示下一 轮 的 输 入。 这种 情况主要是在 进 行 getchar() 新的一行 输 入 时 ,当 输 入了若干字符 ( 不能包含 换 行符 ) 之后,直接 输 入 Ctrl+D ,此 时 的 Ctrl+D 并不是文件 结 束符,而只是相当于 换 行符的功能,即 结 束当前的 输 入。以上面的代 码 段 为 例,如果 执 行 时输 入 abc ,然后 Ctrl+D ,程序 输 出 结 果 为 : abcabc 注意 : 第一 组 abc 为 从 终 端 输 入的,然后 输 入 Ctrl+D ,就 输 出第二 组 abc ,同 时 光 标 停在第二 组 字符的 c 后面 , 然后可以 进 行新一次的 输 入。 这时 如果再次 输 入 Ctrl+D , 则 起到了文件 结 束符的作用, 结 束 getchar ()。 如果 输 入 abc 之后,然后回 车 , 输 入 换 行符的 话 , 则终 端 显 示 为 : abc // 第一行, 带 回 车 abc // 第二行 // 第三行 其中第一行 为终 端 输 入,第二行 为终 端 输 出,光 标 停在了第三行 处 ,等待新一次的 终 端 输 入。 从 这 里也可以看出 Ctrl+D 和 换 行符分 别 作 为 行
转载于:https://my.oschina.net/xiaoyunhu/blog/5951