user-0 提问: getchar、putchar和getc、puts的问题。

回复:
user: user-1
content: 引用 30 楼 lm_whales 的回复: 每从stdin流中获取一个字符，stdin便少一个字符（stdin内部，维持一个队列） 当无字符可用时，就会等待用户输入

user: user-1
content: 引用 27 楼 u013163178 的回复:getchar你是想说getchar并不是直接从键盘获得字符，而是我们把字符字符放到stdin流中，只有按下回车键，stdin才被刷新，这时getchar就可以从中获取字符，并把它赋值给c让后输出来，每从stdin流中获取一个字符，stdin便少一个字符，自动刷新一次，getchar便再次获得字符，一直到stdin中没有字符，就不会在刷新，是这个意思吗 是这样的 只流缓冲空的时候，getchar这样的流输入，才会等待用户，从键盘输入。 只有接收到回车的时候，putchar这样的流输出，才会自动刷新流缓冲，数据才会输出到屏幕。

user: user-1
content: 引用 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

user: user-2
content: 引用 23 楼 fjzhtaobao 的回复:假如有一个无符号8位数据255赋给一个byte类型数据 a；溢出后的a是多少？a=-1?a=0?a=-2? a=255

user: user-3
content: 引用 16 楼 lm_whales 的回复:[quote=引用 15 楼 u013163178 的回复:] 我运行了一遍，感觉是一样的啊，空格和回车都是一样的 不是一不一样的问题。 是逻辑问题 第一个程序： 你希望输入一个字符，输出一个字符，才会写成第一个程序那种形式 实际上，是你输入一行，它输出一行，和你的预期完全不符。 这是一种设计错误。 第二个程序 设计的就是输入一整行，接着输出一整行。 结果完全符合要求。   [/quote]不知道为什么putchar能输出字符串，明明用的getchar和putchar却能输出和获得字符串

user: user-4
content: 假如有一个无符号8位数据255赋给一个byte类型数据 a；溢出后的a是多少？a=-1?a=0?a=-2?

user: user-5
content: 每天看你们的回复就感觉自己又涨姿势了

user: user-0
content: 谢谢大家的讨论，我已经明白了。十八楼说的很清楚。

user: user-6
content: 18楼的分析非常彻底，你单单从结果来看，确实看不出123来。

user: user-3
content: 引用 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中没有字符，就不会在刷新，是这个意思吗

user: user-1
content: 引用 19 楼 user-8 的回复:另外进阶了以后，就会明白gets其实及其不安全，所以才有fgets及gets_s这样的存在。 引用 18 楼 user-8 的回复:均是死循环？。。。。。。 不是的。。。。。。 运行效果完全相同？。。。。 也不是的，核心概念：流  你这个解释和，比较清晰，不过楼主； 仅仅从，程序运行时的，输入和输出，来看问题的，所以看到的难免片面。

user: user-7
content: 关于功能上来说，是因为加了一个while循环，所以有了一个功能一样的错觉，但是从实现角度来说，这个逻辑是有问题的。第一种是不停的从缓冲区读取字符，然后每getchar一次就putchar一次。而后者是一次性读取出来，然后再由puts一次性输出。完全就是不同的概念。  至于安全问题，可以看一下这里：http://www.360doc.com/content/11/0610/16/6295074_126040631.shtml

user: user-8
content: 另外进阶了以后，就会明白gets其实及其不安全，所以才有fgets及gets_s这样的存在。

user: user-8
content: 均是死循环？  不是的，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的次数。  核心概念：流

user: user-1
content: 至于，gets 一直都是这么用的； 直到有一天，发现这有安全问题； 于是增加了gets_s 来替换gets 如此而已。

user: user-1
content: 引用 15 楼 u013163178 的回复:我运行了一遍，感觉是一样的啊，空格和回车都是一样的 不是一不一样的问题。 是逻辑问题 第一个程序： 你希望输入一个字符，输出一个字符，才会写成第一个程序那种形式 实际上，是你输入一行，它输出一行，和你的预期完全不符。 这是一种设计错误。 第二个程序 设计的就是输入一整行，接着输出一整行。 结果完全符合要求。

user: user-3
content: 我运行了一遍，感觉是一样的啊，空格和回车都是一样的

user: user-3
content: 引用 11 楼 lm_whales 的回复:1）这些都是缓冲IO函数，用非缓冲，IO函数就不同了  2）getchar只接收一个字符，还要等到输入回车，才会开始读取。    所以，要求输入时，必须一个字符一个回车，并且回车要设法处理掉。     所以，对于第一个程序，输入多个字符，再回车，这种输入是不正确的，属于非法输入；    由于这个程序，并无容错功能，所以输入多个字符，结果不正确，是理所当然的。        至于第二个程序，输入整行，输出整行用 gets,gets_s,puts     这个设计，没有那么明显的失误        运行结果也符合要求。    和上一个完全不同。好像有一点区别，gets_比gets安全些

user: user-3
content: 引用 3 楼 Benjaminzhou93 的回复:本来想测测 getchar 和 gets 空格有什么区别 但是vs2013报错编译失败你吧gets换成gets_s就可以了吧

user: user-7
content: 引用 8 楼 Benjaminzhou93 的回复:[quote=引用 7 楼 Benjaminzhou93 的回复:] [quote=引用 6 楼 Adol1111 的回复:] 这样写怎样： #define gets gets_s[/quote] 试了下没编译通过[/quote] gets_s是微软自己重写的库函数啊，你用#define改名做什么....这不是没区别么