鱼C论坛

 找回密码
 立即注册
查看: 4143|回复: 11

关于getchar()输入字符的问题,真的很难

 关闭 [复制链接]
发表于 2012-3-16 22:02:23 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 湮汐 于 2012-3-16 22:11 编辑

#include <stdio.h>
#include <stdlib.h>

void main()
{
      FILE *fp;
      char ch, filename[20];

      printf("Please input the filename you want to write: ");
      scanf("%s", filename);
      
      if( !(fp = fopen(filename, "wt+")))
      {
            printf("Cannot open the file!\n");
            exit(0);   // 终止程序
      }

      printf("Please input the sentences you want to write: ");
      ch = getchar();  // 请思考……
      ch = getchar();
      while( ch != EOF )   // ctrl + z
      {
            fputc(ch, fp);
                       ch = getchar();

      }

      fclose(fp);
}

我想知道为什么这里能够输入一个字符串?按常理说这里不是应该是一个字符的吗?
而且为什么要在输入回车之后再输入eof(ctrl+z)才有效呢?
未命名.jpg
真的很难的,搞的我纠结死了!。



小甲鱼最新课程 -> https://ilovefishc.com
发表于 2012-3-16 22:39:13 | 显示全部楼层
getchar的确能读取很多字符,因为你那是个循环。
你这里有个循环只要条件不满足就一直循环。
所以你输入的ctrl z也当成getchar的字符了
退出循环之后才管用
小甲鱼最新课程 -> https://ilovefishc.com
 楼主| 发表于 2012-3-16 22:41:01 | 显示全部楼层

其实 循环我懂,我也知道为什么可以度很多字符。最纠结的是为啥我要先回车,再输入eof才有效,在回车之前输入的eof都无效呢?
小甲鱼最新课程 -> https://ilovefishc.com
发表于 2012-3-16 23:04:35 | 显示全部楼层
不太懂:dizzy:
小甲鱼最新课程 -> https://ilovefishc.com
发表于 2012-3-17 01:33:41 | 显示全部楼层
你可以自己调试一下你的程序。
当你输入字符时,比如:
Please input the sentences you want to write:asdfsadaf 0d0a
这些字符在输入缓冲区中包括你按下的回车,ch的值是一个一个读取的。
至于EOF 它的值实际上就是 -1,你输入EOF 它会一个一个的读取,他是文件结束返回的一个值,你在查阅一下有关EOF的资料看看。
你也可以用这个试试:
while(scanf("%d",&xxx) != EOF)
小甲鱼最新课程 -> https://ilovefishc.com
发表于 2012-3-17 01:34:50 | 显示全部楼层
你可以自己调试一下你的程序。
当你输入字符时,比如:
Please input the sentences you want to write:asdfsadaf 0d0a
这些字符在输入缓冲区中包括你按下的回车,ch的值是一个一个读取的。
至于EOF 它的值实际上就是 -1,你输入EOF 它会一个一个的读取,他是文件结束返回的一个值,你在查阅一下有关EOF的资料看看。
你也可以用这个试试:
while(scanf("%d",&xxx) != EOF)
小甲鱼最新课程 -> https://ilovefishc.com
发表于 2012-3-17 02:12:26 | 显示全部楼层
代码如下
---------------------------------------------------------
int main()
{
char ch;
int count = 0;
cin.get(ch);
while(cin.fail()==false)
{
cout << ch;
count++;
cin.get(ch);
}
cout << "\n" << count << "characters read\n";
return 0;
}
---------------------------------------------------------
Vc++ 6.0控制台模式下(^z在Vc中模拟文件尾)
为什么输入一串字符加^z后,回车,程序不会结束??!!

比如输入:abcd^z + 回车
程序回显 abcd

按道理
当读到^z时,检测到了文件尾,cin将eofbit,failbit都设为1
如果eofbit或failbit设为1,cin.fail则返回true,应该结束程序了,调试中为什么不结束?

输入:abcd + 回车
程序回显:abcd + 换行符(看不见),然后等待输入,此时按下^Z + 回车可以

为什么上一种情况不可以?
困惑,寻找解答,谢谢!!


答案:
原因分析如下:

输入缓冲是行缓冲。当从键盘上输入一串字符并按回车后,这些字符会首先被送到输入缓冲区中存储。每当按下回车键后,cin.get() 就会检测 输入缓冲区中是否有了可读的数据。cin.get() 还会对键盘上是否有作为流结束标志的 Ctrl+Z 或者 Ctrl+D 键按下作出检查,其检查的方式有两种:阻塞式以及非阻塞式。

阻塞式检查方式指的是只有在回车键按下之后才对此前是否有 Ctrl+Z 组合键按下进行检查,非阻塞式样指的是按下 Ctrl+ D 之后立即响应的方式。如果在按 Ctrl+D 之前已经从键盘输入了字符,则 Ctrl+D的作用就相当于回车,即把这些字符送到输入缓冲区供读取使用,此时Ctrl+D不再起流结束符的作用。如果按 Ctrl+D 之前没有任何键盘输入,则 Ctrl+D 就是流结束的信号。

Windows系统中一般采用阻塞式检查 Ctrl+Z、Unix/Linux系统下一般采用非阻塞式的检查 Ctrl+D。楼主是在Windows系统下,因此使用阻塞式的 Ctrl+Z 来标识流的结束。

这种阻塞式的方式有一个特点:只有按下回车之后才有可能检测在此之前是否有Ctrl+Z按下。还有一个特点就是:如果输入缓冲区中有可读的数据则不会检测Ctrl+Z(因为有要读的数据,还不能认为到了流的末尾)。还有一点需要知道:Ctrl+Z产生的不是一个普通的ASCII码值,也就是说它产生的不是一个字符,所以不会跟其它从键盘上输入的字符一样能够存放在输入缓冲区。明白了这几点之后就可以来解释楼主提出的问题了。

从键盘上输入abcd^z 加 回车之后在Windows系统上是这样处理的:由于回车的作用,前面的 abcd 等字符被送到输入缓冲区(注意:上面说过了,^z不会产生字符,所以更不会存储到输入缓冲区,缓冲区中没有 ^z 的存在)。这时,cin.get() 检测到输入缓冲区中已经有数据存在(因此不再检查是否有 ^z 的输入),于是从缓冲中读取相应的数据。如果都读取完了,则输入缓冲区重新变为空, cin.get() 等待新的输入。可见,尽管有 ^z 按下,但是由于在此之前还有其它输入字符(abcd),所以流也不会结束。

因此,输入流结束的条件就是:^z 之前不能有任何字符输入(回车除外),否则 ^z 起不到流结束的作用。

还有个问题
如果输入abcd^zabcd
程序回显 abcd
并等待输入,也就是^Z后的不再显示了

-----------------------------------------------
如果输入缓冲区中有可读的数据则不会检测Ctrl+Z(因为有要读的数据,还不能认为到了流的末尾)。还有一点需要知道:Ctrl+Z产生的不是一个普通的ASCII码值,也就是说它产生的不是一个字符,所以不会跟其它从键盘上输入的字符一样能够存放在输入缓冲区。

>> 如果输入abcd^zabcd
>> 程序回显 abcd
>> 并等待输入,也就是^Z后的不再显示了
>> 为什么后面的却没有处理呢?
所以可以把这种情况下的 ^z 理解为键盘输入的终止,但不是流的终止
小甲鱼最新课程 -> https://ilovefishc.com
发表于 2012-3-17 15:33:40 | 显示全部楼层
我明白你迷惑在哪了。
我想知道为什么这里能够输入一个字符串?按常理说这里不是应该是一个字符的吗?
而且为什么要在输入回车之后再输入eof(ctrl+z)才有效呢?

不是输入eof,不需要输入eof。
eof的意思就是一个负数,一般是-1,。
你按下一堆字符 sdsdl和 ctrl+z 系统不会把^z解释成-1.
如果当你先按下ctrl+z是在按lsjdfsdfl时,系统会解释为直接退出。
这就是你为什么要按完回车在按ctrl+z才有效的原因。

另外在linux下eof好像是要按ctrl+d 。
小甲鱼最新课程 -> https://ilovefishc.com
 楼主| 发表于 2012-3-17 16:22:38 | 显示全部楼层
ghostotem 发表于 2012-3-17 15:33
我明白你迷惑在哪了。

不是输入eof,不需要输入eof。

朋友,你好,你没有明白我的意思,但还是很感谢你这么耐心的为我解答。我知道不需要输入字母eof。我是说为什么输入I love fishc1^Z[enter]后还需要输入一个^Z?
按理来说,对这个程序最直接的理解,不是只要碰到^Z就停止了吗?
为什么^Z要在【enter】只有才有作用呢?
小甲鱼最新课程 -> https://ilovefishc.com
 楼主| 发表于 2012-3-17 16:56:59 | 显示全部楼层
终于搞明白了
详情请见:http://www.cnblogs.com/nuddle/archive/2010/04/25/1719768.html
说实在点,可以说是vc++6.0的一个bug吧!
eof必须在程序新开一行输入才有效,即:程序里要按ctrl+Z 一定要新开一行,否则就是指这一行结束,后面的字符不会显示
例如:abc^Zabc,只会显示abc,因为^Z已经代表这一行结束,而且^Z不会进入缓冲区,更不会计入输入的字符数,像abc^Zabc,相当于只输入三个字符。
小甲鱼最新课程 -> https://ilovefishc.com
发表于 2012-3-17 17:16:54 | 显示全部楼层
跟了下确实是的 file文件生成时 需要读取多少字节已经有记录的 根本不会读取^Z
如果想读取也不会事读取的是-1
顶多自己修改内存读取个1A 这样说明 getchar貌似返回int没什么用
记得看书说 getchar的返回值接收最好定义个int 有点矛盾
小甲鱼最新课程 -> https://ilovefishc.com
发表于 2012-3-18 13:56:27 | 显示全部楼层
Ctrl+z含义是文件结束。!=EOF就是文件不结束时。会一直循环,直到你输入Ctrl+z
小甲鱼最新课程 -> https://ilovefishc.com
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-11-12 02:30

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表