C语言_scanf()和getchar() 使用[粗俗易懂]
原文地址:http://blog.csdn.net/hao5743/article/details/6939661/,以下是我重新整理的以下。
问题描述一:【分析scanf()和getchar()读取字符】
scanf(), getchar()等都是标准输入函数,一般人都会觉得这几个函数非常简单,没什么特殊的。但是有时候却就是因为使用这些函数除了问题,却找不出其中的原因。下面先看一个很简单的程序:
程序:

#include <stdio.h>
int main()
{
char ch1, ch2;
scanf("%c", &ch1);
scanf("%c", &ch2);
printf("%d %d\n", ch1, ch2);
return 0;
}

或者是:

#include <stdio.h>
int main()
{
char ch1, ch2;
ch1 = getchar();
ch2 = getchar();
printf("%d %d\n", ch1, ch2);
return 0;
}

程序的本意很简单,就是从键盘读入两个字符,然后打印出这两个字符的ASCII码值。可是执行程序后会发现除了问题:当从键盘输入一个字符后,就打印出了结果,根本就没有输入第二个字符程序就结束了。例如用户输入字符'a', 打印结果是97,10。这是为什么呢?
【分析】:
首先我们呢看一下输入操作的原理, 程序的输入都建有一个缓冲区,即输入缓冲区。一次输入过程是这样的,当一次键盘输入结束时会将输入的数据存入输入缓冲区,而cin函数直接从输入缓冲区中取数据。正因为cin函数是直接从缓冲区取数据的,所以有时候当缓冲区中有残留数据时,cin函数会直接取得这些残留数据而不会请求键盘输入,这就是例子中为什么会出现输入语句失效的原因!
其实这里的10恰好是回车符!这是因为scanf()和getchar()函数是从输入流缓冲区中读取值的,而并非从键盘(也就是终端)缓冲区读取。而读取时遇到回车(\n)而结束的,这个\n会一起读入输入流缓冲区的,所以第一次接受输入时取走字符后会留下字符\n,这样第二次的读入函数直接从缓冲区中把\n取走了,显然读取成功了,所以不会再从终端读取!这就是为什么这个程序只执行了一次输入操作就结束的原因!
问题描述二:【分析scanf()和gets()读取字符串】
首先我们看一下scanf()读取字符串的问题:
程序:

#include <stdio.h>
int main()
{
char str1[20], str2[20];
scanf("%s",str1);
printf("%s\n",str1);
scanf("%s",str2);
printf("%s\n",str2);
return 0;
}

程序的功能是读入一个字符串输出,在读入一个字符串输出。可我们会发现输入的字符串中不能出现空格,例如:
测试一输入:
Hello world!
输出:
Hello
world!
【分析】到此程序执行完毕,不会执行第二次的读取操作!这个问题的原因跟问题一类似,第一次输入Hello world!后,字符串Hello world!都会被读到输入缓冲区中,而scanf()函数取数据是遇到回车、空格、TAB就会停止,也就是第一个scanf()会取出"Hello",而"world!"还在缓冲区中,这样第二个scanf会直接取出这些数据,而不会等待从终端输入。
测试二:
Hello[Enter]
Hello[输出]
world[Enter]
world[输出]
【分析】程序执行了两次从键盘读入字符串,说明第一次输入结束时的回车符被丢弃!即:scanf()读取字符串会舍弃最后的回车符!
我们再看一下gets()读取字符串的情况:
用scanf来读取一个字符串时,字符串中是不可以出现空格的,一旦出现空格,后面的数据就会舍弃残留在缓冲区中。其实有另外一个函数是可以接受空格的,那就是gets(),下面我们看一下这个函数的应用,我们把程序2改动一下:
程序:

#include <stdio.h>
int main()
{
char str1[20], str2[20];
gets(str1);
printf("%s\n",str1);
gets(str2);
printf("%s\n",str2);
return 0;
}

测试:
Hello world! [输入]
Hello world! [输出]
12345 [输入]
12345 [输出]
【分析】显然与上一个程序的执行情况不同,这次程序执行了两次从键盘的读入,而且第一个字符串取了Hello world! 接受了空格符,而没有像上一个程序那样分成了两个字符串!所以如果要读入一个带空格符的字符串时因该用gets(), 而不宜用scanf()!
问题描述三:【getchar()暂停程序,查看程序执行结果)】
不知道大家有没有遇到过这样的问题,有的编译器程序执行完后的结果界面不会停下而是一闪就没了,以至于看不到执行结果。所以很多人在程序最后加上getchar()语句,目的是想让程序执行完后停下来,等待从终端接收一个字符再结束程序。可是发现有时候这样根本没用,程序照样跳出去了。这是为什么呢?
【分析】原因跟上面例子讲的一样,是因为输入缓冲区中还有数据,所以getchar()会成果读到数据,所以就跳出了!
【总结】
第一:要注意不同的函数是否接受空格符、是否舍弃最后的回车符的问题!
读取字符时:
scanf()以Space、Enter、Tab结束一次输入,不会舍弃最后的回车符(即回车符会残留在缓冲区中);
getchar()以Enter结束输入,也不会舍弃最后的回车符;
读取字符串时:
scanf()以Space、Enter、Tab结束一次输入
gets()以Enter结束输入(空格不结束),接受空格,会舍弃最后的回车符!
第二:为了避免出现上述问题,必须要清空缓冲区的残留数据,可以用以下的方法解决:
方法1:C语言里提供了函数清空缓冲区,只要在读数据之前先清空缓冲区就没问题了!
这个函数是fflush(stdin)。
方法2:自己取出缓冲区里的残留数据。
(说实话这个语句我也没看懂,呵呵!为什么格式控制是这样的!希望高手指点一下!)
scanf("%[^\n]",string);
C语言_scanf()和getchar() 使用[粗俗易懂]的更多相关文章
- 基于C语言EOF与getchar()的使用详解
转自:http://www.jb51.net/article/36848.htm 大师级经典的著作,要字斟句酌的去读,去理解.以前在看K&R的The C Programming Langu ...
- c语言:getch() getchar()
1.getchar();从键盘读取一个字符并输出,该函数的返回值是输入第一个字符的ASCII码:若用户输入的是一连串字符,函数直到用户输入回车时结束,输入的字符连同回车一起存入键盘缓冲区.若程序中有后 ...
- 粗俗易懂的SQL存储过程在.NET中的实例运用
整理了一下存储过程在项目中的运用,防止遗忘,便记录于此!存储过程(Stored Procedure)是一组为了完成特定功能的SQL语句集,经编译后存储在数据库中.用户通过指定存储过程的名字并给出参数( ...
- Linux C 字符函数 getchar()、putchar() 与 EOF 详解
首先给出<The_C_Programming_Language>这本书中的例子: #include <stdio.h> int main() { int c; c = getc ...
- getchar
getchar函数每次只从缓冲区中接受一个字符. getchar有一个int型的返回值. 当程序调用getchar时,程序就等着用户按键,用户输入的字符被存放在键盘缓冲区中,直到用户按回车为止(回车字 ...
- python为什么是高级语言和解释型编程语言?它是如何粘合其它语言写的代码的?
学习python之初,不知道大家对于python有没有疑惑,应当是有的.这里我整理出来了自己的一些疑惑,供大家参考. 为什么python是高级程序设计语言 Java,C,C++这些语言是高级语言, ...
- Android注入完全剖析
0 前沿 本文主要分析了一份实现Android注入的代码的技术细节,但是并不涉及ptrace相关的知识,所以读者如果不了解ptrace的话,最好先学习下ptrace原理再来阅读本文.首先,感谢源代码的 ...
- Thrift 的原理和使用
thrift 的原理和使用 Thrift 架构 Thrift是一个跨语言的服务部署框架,最初由Facebook于2007年开发,2008年进入Apache开源项目.Thrift通过IDL(Interf ...
- 使用python爬取P站图片
刚开学时有一段时间周末没事,于是经常在P站的特辑里收图,但是P站加载图片的速度比较感人,觉得自己身为计算机专业,怎么可以做一张张图慢慢下这么low的事,而且这样效率的确也太低了,于是就想写个程序来帮我 ...
随机推荐
- 我看过得最易懂的一段AOP的解释
http://blog.csdn.net/zhangliangzi/article/details/51648032 面向切面编程(AOP是Aspect Oriented Program的首字母缩写) ...
- python3 第十四章 - 数据类型之Dictionary(字典)
在python中字典是另一种可变容器模型,且可存储任意类型对象. 字典的每个键值(key=>value)对用冒号(:)分割,每个对之间用逗号(,)分割,整个字典包括在花括号({})中 ,格式如下 ...
- 《Java编程的逻辑》终于上市了!
2018年1月下旬,<Java编程的逻辑>终于出版上市了! 这是老马过去两年死磕到底.无数心血的结晶啊! 感谢"博客园"的广大读者们,你们对老马文章的极高评价.溢美之词 ...
- linux_系统调优
linux如何调优? 1. 关闭SELLinux功能,美国国家安全局对于强制访问控制实现,生产场景也是关闭 cat /etc/selinux/config | grep '^SELINUX=' # 查 ...
- 流API--流的基础知识
流接口--BaseStream接口 流API定义了几个流接口,这些接口包含在java.util.stream中.BaseStream是基础接口,它定义了所有流都可以使用的基本功能.我们来看一下源码: ...
- 如何书写优雅、漂亮的SQL脚本?
本篇来聊聊如何书写漂亮.整洁.优雅的SQL脚本,下面这些是我个人总结.整理出来的.姑且做个抛砖引玉吧,呵呵,欢迎大家一起来讨论. 我们首先来看看一段创建数据表的脚本(如下所示),你是否觉得有什么不 ...
- 01-Go命令与基础
什么是Go? Go是一门并发支持.垃圾回收的编译型系统编程语言,旨在创造一门具有在静态编译语言的高性能和动态的高效开之间拥有良好平衡点的一门编程语言. Go的主要特点有哪些? 类型安全和内存安全 以非 ...
- fopen fclose feof fgets fetl
fopen :Open file, or obtain information about open files 例如 fid = fopen(filename, permission)%许可包括: ...
- 赋值号和printf
1.赋值号会自动转换类型: int a= 2.1; printf(‘‘%d’’,a); //输出结果是2 2.printf不会转换类型,而是直接将内存中表示的补码数拿出来,最明显的就是 ...
- Keepalived+LVS 实现高负载均衡Web集群
一.原理及简介: 1.1 Keepalived简介 Keepalived是Linux下一个轻量级别的高可用解决方案.Keepalived起初是为LVS设计的,专门用来监控集群系统中各个服务节 ...