getchar、putchar和getc、puts的问题。

幸福的面包 诊断软件开发工程师  2013-12-31 06:25:11
#include <stdio.h>

int main()
{
char c;

while((c = getchar()) != EOF)
putchar(c);
return 0;
}

运行结果


int main()
{
char foor[20];

while(gets(foor) != NULL)
puts(foor);
return 0;
}
运行结果

以上两个程序,均是死循环。运行效果完全相同。?
...全文
248 点赞 收藏 31
写回复
31 条回复
lm_whales 2014年01月03日
引用 30 楼 lm_whales 的回复:
每从stdin流中获取一个字符,stdin便少一个字符(stdin内部,维持一个队列) 当无字符可用时,就会等待用户输入
回复 点赞
lm_whales 2014年01月03日
引用 27 楼 u013163178 的回复:
getchar你是想说getchar并不是直接从键盘获得字符,而是我们把字符字符放到stdin流中,只有按下回车键,stdin才被刷新,这时getchar就可以从中获取字符,并把它赋值给c让后输出来,每从stdin流中获取一个字符,stdin便少一个字符,自动刷新一次,getchar便再次获得字符,一直到stdin中没有字符,就不会在刷新,是这个意思吗
是这样的 只流缓冲空的时候,getchar这样的流输入,才会等待用户,从键盘输入。 只有接收到回车的时候,putchar这样的流输出,才会自动刷新流缓冲,数据才会输出到屏幕。
回复 点赞
lm_whales 2014年01月02日
引用 24 楼 u013163178 的回复:
[quote=引用 16 楼 lm_whales 的回复:] [quote=引用 15 楼 u013163178 的回复:] 我运行了一遍,感觉是一样的啊,空格和回车都是一样的
不是一不一样的问题。 是逻辑问题 第一个程序: 你希望输入一个字符,输出一个字符,才会写成第一个程序那种形式 实际上,是你输入一行,它输出一行,和你的预期完全不符。 这是一种设计错误。 第二个程序 设计的就是输入一整行,接着输出一整行。 结果完全符合要求。 [/quote]不知道为什么putchar能输出字符串,明明用的getchar和putchar却能输出和获得字符串[/quote] 因为是缓冲IO 或者叫 流IO 不论输入输出,都是先放在缓冲里的 只有遇到回车,才开始真的读取,和输出 这里有两个输入输出过程 1)输入 1.1) 1个是用户敲键盘,输入数据到输入流缓冲 1.2) 1个是程序中 getchar() 这个函数,从输入缓冲读取字符 并赋值给c 流输入并不是用户输入一个,getchar()就会执行一次 而是getchar()函数,一直在等待,直到输入流被更新; 即用户输入回车的时候,才开始读取流缓冲中的数据; 而只要流缓冲有数据,getchar()就可以不用等待,一直读取,直到流缓冲被读空。 2)输出 2.1) 1个是 putchar()函数直接把 c 输出到流缓冲; 2.2) 1个是,流缓冲等待输出回车换行,才开始清理流缓冲; 一次性,把一行数据,输出到 stdout 对应的文件或设备中(屏幕)。 此时,输出流缓冲被清空,后面就可以重新输出数据到流缓冲了。 那么,现在看看第一个程序的输入输出过程 程序中
while((c = getchar())!=EOF)
{
    putchar(c);
}
每次调用getchar,把一个字符读到c中,如果缓冲没有数据, 那么就一直等待用户输入,直到用户输入回车('\n'); 此时getchar返回输入流缓冲中,接收的第一个字符; 输入流缓冲,此时,接收一行字符,包括回车换行(‘\n’)。 getchar返回后,只有第一个字符赋值给了c 其他字符还在输入流缓冲。 此时程序调用putchar函数输出c 只要这个字符不是‘\n’ ,那么这个字符只是输出到流缓冲,并不输出到屏幕。 接着又是调用getchar, 然后 putchar 当 getchar读到‘\n’时,接着putchar 输出‘\n’ 此时用户输入的一整行数据,才开始输出到屏幕 结果就是输入一行,输出一行 然后,再重新开始这个过程。 直到读到文件结束标志,此时c == EOF,就是键盘输入ctrl Z ,显示 ^Z,结束程序的运行。 linux ,unix 键盘输入ctrl D ,显示 ^D
回复 点赞
赵4老师 2014年01月02日
引用 23 楼 fjzhtaobao 的回复:
假如有一个无符号8位数据255赋给一个byte类型数据 a;溢出后的a是多少?a=-1?a=0?a=-2?
a=255
回复 点赞
li4c 2014年01月02日
引用 16 楼 lm_whales 的回复:
[quote=引用 15 楼 u013163178 的回复:] 我运行了一遍,感觉是一样的啊,空格和回车都是一样的
不是一不一样的问题。 是逻辑问题 第一个程序: 你希望输入一个字符,输出一个字符,才会写成第一个程序那种形式 实际上,是你输入一行,它输出一行,和你的预期完全不符。 这是一种设计错误。 第二个程序 设计的就是输入一整行,接着输出一整行。 结果完全符合要求。 [/quote]不知道为什么putchar能输出字符串,明明用的getchar和putchar却能输出和获得字符串
回复 点赞
AT90_SCR 2014年01月02日
假如有一个无符号8位数据255赋给一个byte类型数据 a;溢出后的a是多少?a=-1?a=0?a=-2?
回复 点赞
Bird_1989 2014年01月02日
每天看你们的回复就感觉自己又涨姿势了
回复 点赞
幸福的面包 2014年01月02日
谢谢大家的讨论,我已经明白了。十八楼说的很清楚。
回复 点赞
coding梦想_起点 2014年01月02日
18楼的分析非常彻底,你单单从结果来看,确实看不出123来。
回复 点赞
li4c 2014年01月02日
引用 26 楼 lm_whales 的回复:
[quote=引用 24 楼 u013163178 的回复:] [quote=引用 16 楼 lm_whales 的回复:] [quote=引用 15 楼 u013163178 的回复:] 我运行了一遍,感觉是一样的啊,空格和回车都是一样的
不是一不一样的问题。 是逻辑问题 第一个程序: 你希望输入一个字符,输出一个字符,才会写成第一个程序那种形式 实际上,是你输入一行,它输出一行,和你的预期完全不符。 这是一种设计错误。 第二个程序 设计的就是输入一整行,接着输出一整行。 结果完全符合要求。 [/quote]不知道为什么putchar能输出字符串,明明用的getchar和putchar却能输出和获得字符串[/quote] 因为是缓冲IO 或者叫 流IO 不论输入输出,都是先放在缓冲里的 只有遇到回车,才开始真的读取,和输出 这里有两个输入输出过程 1)输入 1.1) 1个是用户敲键盘,输入数据到输入流缓冲 1.2) 1个是程序中 getchar() 这个函数,从输入缓冲读取字符 并赋值给c 流输入并不是用户输入一个,getchar()就会执行一次 而是getchar()函数,一直在等待,直到输入流被更新; 即用户输入回车的时候,才开始读取流缓冲中的数据; 而只要流缓冲有数据,getchar()就可以不用等待,一直读取,直到流缓冲被读空。 2)输出 2.1) 1个是 putchar()函数直接把 c 输出到流缓冲; 2.2) 1个是,流缓冲等待输出回车换行,才开始清理流缓冲; 一次性,把一行数据,输出到 stdout 对应的文件或设备中(屏幕)。 此时,输出流缓冲被清空,后面就可以重新输出数据到流缓冲了。 那么,现在看看第一个程序的输入输出过程 程序中
while((c = getchar())!=EOF)
{
    putchar(c);
}
每次调用getchar,把一个字符读到c中,如果缓冲没有数据, 那么就一直等待用户输入,直到用户输入回车('\n'); 此时getchar返回输入流缓冲中,接收的第一个字符; 输入流缓冲,此时,接收一行字符,包括回车换行(‘\n’)。 getchar返回后,只有第一个字符赋值给了c 其他字符还在输入流缓冲。 此时程序调用putchar函数输出c 只要这个字符不是‘\n’ ,那么这个字符只是输出到流缓冲,并不输出到屏幕。 接着又是调用getchar, 然后 putchar 当 getchar读到‘\n’时,接着putchar 输出‘\n’ 此时用户输入的一整行数据,才开始输出到屏幕 结果就是输入一行,输出一行 然后,再重新开始这个过程。 直到读到文件结束标志,此时c == EOF,就是键盘输入ctrl Z ,显示 ^Z,结束程序的运行。 linux ,unix 键盘输入ctrl D ,显示 ^D [/quote]
while((c = getchar())!=EOF)
{
    putchar(c);
}
getchar你是想说getchar并不是直接从键盘获得字符,而是我们把字符字符放到stdin流中,只有按下回车键,stdin才被刷新,这时getchar就可以从中获取字符,并把它赋值给c让后输出来,每从stdin流中获取一个字符,stdin便少一个字符,自动刷新一次,getchar便再次获得字符,一直到stdin中没有字符,就不会在刷新,是这个意思吗
回复 点赞
lm_whales 2014年01月01日
引用 19 楼 ForestDB 的回复:
另外进阶了以后,就会明白gets其实及其不安全,所以才有fgets及gets_s这样的存在。
引用 18 楼 ForestDB 的回复:
均是死循环?。。。。。。 不是的。。。。。。 运行效果完全相同?。。。。 也不是的,核心概念:流
你这个解释和,比较清晰,不过楼主; 仅仅从,程序运行时的,输入和输出,来看问题的,所以看到的难免片面。
回复 点赞
Adol1111 2014年01月01日
关于功能上来说,是因为加了一个while循环,所以有了一个功能一样的错觉,但是从实现角度来说,这个逻辑是有问题的。第一种是不停的从缓冲区读取字符,然后每getchar一次就putchar一次。而后者是一次性读取出来,然后再由puts一次性输出。完全就是不同的概念。 至于安全问题,可以看一下这里:http://www.360doc.com/content/11/0610/16/6295074_126040631.shtml
回复 点赞
ForestDB 2014年01月01日
另外进阶了以后,就会明白gets其实及其不安全,所以才有fgets及gets_s这样的存在。
回复 点赞
ForestDB 2014年01月01日
均是死循环? 不是的,getchar和gets都有返回NULL的时候,这时while的条件就不满足了,循环就结束了; 那它们什么时候返回NULL呢?当它们读到EOF的时候; 那控制台怎么输入EOF呢?Windows下就是Ctrl+Z 运行效果完全相同? 也不是的,看上去一样,实际运行的原理还是不一样的。 getchar每次读入一个字符,gets每次读一行(但会丢弃回车),这就是它们的区别; 为什么都是回车之后才有反应?因为标准IO都是有缓冲的,而且是行缓冲, 这意味着“标准输入流”只有在按回车之后,输入的东西才会进入流(输入的东西也包括了回车) 比如,刚进入程序,“标准输入流”中没有任何东西,这时getX会等待输入(还没有进循环体) 用户输入abc,“标准输入流”还是没有东西,直到用户输入回车<cr>,这时“标注输入流”中才有东西: abc<cr> 这时标准输入流有东西了,getX可以返回了, getchar从stdin中读入一个字符a,返回该字符,该字符不为NULL,进入循环体,putchar该字符;然后又回到while,读入下一个字符b,不为NULL,putchar该字符,一直到<cr>,getchar读入<cr>,不为NULL,putchar <cr>产生回车效果,这时stdin空了,等待用户的下一次输入 而gets从stdin中读入abc<cr>,并将abc存入foor(<cr>丢弃),由于成功读入,gets返回foor,它并不是NULL,从而导致进入循环体,puts将输出foor,即abc,同时puts会多输出个回车,然后又回到while,这时stdin已空,程序停下来等待用户的下一次输入 由此可以发现,用户输入 abc<cr> getchar while了四次,而gets只while了一次,这就是它们区别的表现,单纯看输入输出是看不出来的,可以通过debugger跟踪程序的运行,来理解while的过程;也可以通过加一个循环counter,来跟踪while的次数。 核心概念:流
回复 点赞
lm_whales 2014年01月01日
至于,gets 一直都是这么用的; 直到有一天,发现这有安全问题; 于是增加了gets_s 来替换gets 如此而已。
回复 点赞
lm_whales 2014年01月01日
引用 15 楼 u013163178 的回复:
我运行了一遍,感觉是一样的啊,空格和回车都是一样的
不是一不一样的问题。 是逻辑问题 第一个程序: 你希望输入一个字符,输出一个字符,才会写成第一个程序那种形式 实际上,是你输入一行,它输出一行,和你的预期完全不符。 这是一种设计错误。 第二个程序 设计的就是输入一整行,接着输出一整行。 结果完全符合要求。
回复 点赞
li4c 2014年01月01日
我运行了一遍,感觉是一样的啊,空格和回车都是一样的
回复 点赞
li4c 2014年01月01日
引用 11 楼 lm_whales 的回复:
1)这些都是缓冲IO函数,用非缓冲,IO函数就不同了 2)getchar只接收一个字符,还要等到输入回车,才会开始读取。 所以,要求输入时,必须一个字符一个回车,并且回车要设法处理掉。 所以,对于第一个程序,输入多个字符,再回车,这种输入是不正确的,属于非法输入; 由于这个程序,并无容错功能,所以输入多个字符,结果不正确,是理所当然的。 至于第二个程序,输入整行,输出整行用 gets,gets_s,puts 这个设计,没有那么明显的失误 运行结果也符合要求。 和上一个完全不同。
好像有一点区别,gets_比gets安全些
回复 点赞
li4c 2014年01月01日
引用 3 楼 Benjaminzhou93 的回复:
本来想测测 getchar 和 gets 空格有什么区别 但是vs2013报错编译失败
你吧gets换成gets_s就可以了吧
回复 点赞
Adol1111 2014年01月01日
引用 8 楼 Benjaminzhou93 的回复:
[quote=引用 7 楼 Benjaminzhou93 的回复:] [quote=引用 6 楼 Adol1111 的回复:]
这样写怎样: #define gets gets_s[/quote] 试了下没编译通过[/quote] gets_s是微软自己重写的库函数啊,你用#define改名做什么....这不是没区别么
回复 点赞
发动态
发帖子
C语言
创建于2007-09-28

3.2w+

社区成员

24.0w+

社区内容

C语言相关问题讨论
社区公告
暂无公告