scanf()、printf()、getchar()和putchar()这四个函数能够让用户和程序交流,所以被称为输入/输出函数,或简称为I/O函数

这里先结合缓冲输入来讲讲scanf()和getchar()背后的处理机制。还有空格回车输入跟scanf()、getchar()的关联。

对于缓冲输入而言,键盘的输入不是实时被scanf响应的。首先存在缓冲当中。

当遇到换行、缓冲满、程序结束几种情况之一的时候,才会被送到scanf中。

而且scanf是以删除的方式从缓冲区读入数据(来自标准输入设备的数据存储在缓冲区)。读一个数据,该数据就在缓冲区被删掉。

如果scanf需要读取一个数据项,发现缓冲区当前是空的,那么程序就会在scanf代码处阻塞,等待用户输入。

只有scanf函数接收到相应数据项之后,在缓冲区这个数据项清楚,scanf函数返回,程序继续执行。

空白字符(white space)的概念:包含了空格(space)、回车(enter)、制表符(table);

scanf()返回的是成功赋值的数据项数。如果出错或遇到end of file(文件结尾),则返回EOF;

(如果想从键盘输入EOF,使用Ctrl+D或Ctrl+Z)

getchar()是到输入流数据缓冲区一个一个读取数据,调用一次读取缓冲区的首字符,并且删掉该字符。

行缓冲输入:以换行为结束标志;scanf()调用会等待用户按键,当用户按键完之后,就会去缓冲区读数据。

getchar()则是直接去读缓冲区的内容。

例子:混合使用getchar()和scanf()

 //检查输入是否正确。要求输入是整数
int get_int(void)
{
int input;
char ch; while(scanf("%d",&input)!=)
{
while((ch=getchar())!='\n')
putchar(ch);
printf(" is not an integer.\nPlease enter an");
printf("integer value,such as 25,-178,or 3:\n");
}
return input;
}

以上是一个用户输入进行验证的函数,不符合要求的输入,会提示用户再次输入。

当调用该函数的时候,直接敲Enter就会导致scanf()阻塞,光标闪烁,继续等待用户输入。

+++++++++++++++++++++++++++++++++++++++++++++++++++++++

I/O函数的具体用法和说明

1、printf()函数:

打印数据的指令要与待打印数据的类型相匹配。这些符号被称为转换说明。conversion specification

格式:printf(格式字符串,待打印项1,待打印项2…)

格式字符串中要包含待打印项的转换说明。格式字符串是双括号括起来的内容。%符号用来表示转换说明。打印%符号就成了一个问题,解决方法很简单,用两个%%即可。

转换说明把二进制格式存在计算机中的值转换成一系列字符以便于显示。

转换说明与待打印值不匹配会导致一些问题,匹配非常重要。

大部分C函数都有一个返回值,这是函数计算并返回给主调程序(calling program)。

printf()也有返回值,但不是主要功能,是附带用途。检查输出错误时可以用到。

返回打印字符的个数(项数),如果打印错误,会返回一个负值;返回成功打印的项数(成功打印要保证输入符合转换说明的要求);

另外还有转换说明修饰符的概念;

2、scanf()函数

scanf()返回值:

scanf()只返回成功读取的项数;如果没有读取任何项,且只需要读取一个数字而用户却输入一个非数值字符串,scanf()便返回0;

scanf()遇到“文件结尾”时,会返回EOF(EOF是stdio.h中定义的一个特殊值,#define指令把EOF定义为-1);

结合if语句和while语句,可使用scanf()的返回值来检测和处理不匹配输入的问题

scanf什么时候加&,什么时候不加&:scanf的意思是,你把输入的值传到我的这个地址上。

如果你的参数已经是地址了,就不需要用&;

当参数为数据(变量名)时,则使用取址符&;

当参数为地址时,不需要使用取址符&,例如字符串、指针;

3、getchar()和putchar()函数:

二者都属于单字符I/O,只处理字符,而且是一个一个字符地处理。

具体用法:待补充

+++++++++++++++++++++++++++++++++++++++++++++++++++++++

验证输入:

是代码中最复杂的部分:有多种处理方案,可以在用户输入错误的信息时,终止程序。也可以给用户提供有限次或无限次机会重新输入。

程序要做到:当用户遵循指令时程序运行正常。当用户不遵循指令时,程序也能运行正常。

输入实际上是字符流,getchar()函数逐字符读取输入。遵循模块化的编程思想,使用独立函数(模块)来验证输入和管理显示。

文件结尾

无论操作系统使用何种方法检测文件末尾。C语言中,用getchar()读取到的文件结尾时,将返回一个特殊值,即EOF(end of file)的意思。scanf检测到文件结尾时也返回EOF。EOF定义在stdio.h文件中;#define EOF (-1)

为什么是-1,因为-1不对应任何字符,所以该值可用于表示文件结尾。

关键要理解EOF是一个值。标志着文件的结尾,并不是在文件中找得到的符号。

如何使用EOF,把getchar()的值与EOF作比较。如果两值不同,就说明没有到达文件结尾。(如果想从键盘输入EOF,使用Ctrl+D或Ctrl+Z,即模拟EOF)

上升一个层次:

C把输入和输出设备视为存储设备上的普通文件,尤其是把键盘和显示设备视为没个C程序自动打开的文件,stdin表示键盘输入,stdout表示屏幕输出。

设备即文件!

从概念上来讲,C处理的是流而不是直接处理文件。(stream)是一个实际输入或输出映射的理想化数据流。

不同属性和不同种类的输入,由属性更统一的流来表示。于是打开文件的过程就是把流与文件相关联,而且读写都通过流来完成。

缓冲区的概念:

缓冲输入和无缓冲输入都有用武之地。

有些交互式程序也需要无缓冲输入,例如在游戏中,你希望按下一个键就执行相应的指令。

缓冲区(buffer):用户的输入被存储在一个临时存储区,按下Enter键之后,程序才可以使用用户输入的字符。

缓冲的分类:完全缓冲I/O和行缓冲I/O

完全缓冲I/O:当缓冲区被完全填满时才刷新缓冲区,通常出现在文件的输入中。缓冲区的大小取决于系统。

行缓冲I/O:出现换行符时刷新缓冲区。键盘输入通常是行缓冲,所以在按下Enter键后才刷新缓冲区。

刷新缓冲区(即内容被发送到目的地)

总结

的角度去理解数据的输入输出、再结合缓冲区的概念。就能够深刻理解I/O函数背后的处理机制。

再结合重定向的概念,输入输出设备也是文件的概念。从更高层面上理解数据的流动。

+++++++++++++++++++++++++++++++++++++++++++++++++++++++

printf()和scanf()*修饰符:

printf()和scanf()都可以使用*修饰符来修改转换说明的含义。

如果预先不想指定字段宽度,希望通过程序来指定,那么可以用*修饰符代替字段宽度。

但是要用一个参数告诉函数,字段宽度应该是多少。

如果转换说明是%*d,那么参数列表应该包含*和d对应的值。

这个技巧也可以用于浮点值指定精度和字段宽度

1 int width =3;
2 int precision=3;
3 float weight = 68.1233;
4 printf("Weight = %*.*f\n",width,precision,weight);

返回值会变成:Weight = 68.123

scanf()中*的用法与此不同,把*放在%和转换字符之间。会使得scanf()跳过相应的输出项。

+++++++++++++++++++++++++++++++++++++++++++++++++++++++

参考链接:

C语言中scanf函数与空格回车:https://blog.csdn.net/u011499425/article/details/52606973

C语言初步学习I/O函数scanf、getchar、printf和putchar的更多相关文章

  1. C语言编程学习:使用函数必须知道的3点注意事项

    C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构.C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现 ...

  2. C语言如何在可变参数函数中使用printf?

    我要将printf外面再包上一层:void fun(const char* fmt,...) {........printf(fmt,...);........}这种函数怎么写? 对比下printf与 ...

  3. es6函数模块-------初步学习

    初步学习: 函数参数允许尾逗号 function clownsEverywhere( param1, param2, //param2后面有逗号 ) { } 函数参数可以赋初值 利用解构赋值默认值结合 ...

  4. 初探swift语言的学习笔记四(类对象,函数)

    作者:fengsh998 原文地址:http://blog.csdn.net/fengsh998/article/details/29606137 转载请注明出处 假设认为文章对你有所帮助,请通过留言 ...

  5. C语言课程学习的总结

    C语言课程学习的总结 学习C程序这门课一年了,这是我们学的第一门专业课.在大学里,C语言不但是计算机专业的必修课程而且也是非计算机专业学习计算机基础的一门必修课程.所以作为我这个计算机专业的学生来说当 ...

  6. C语言范例学习04

    第三章 算法 前言:许多人对算法的看法是截然不同的,我之前提到过了.不过,我要说的还是那句话:算法体现编程思想,编程思想指引算法. 同时,有许多人认为简单算法都太简单了,应当去学习一些更为实用的复杂算 ...

  7. C语言范例学习03-中

    栈和队列 这两者都是重要的数据结构,都是线性结构.它们在日后的软件开发中有着重大作用.后面会有实例讲解. 两者区别和联系,其实总结起来就一句.栈,后进先出:队列,先进先出. 可以将栈与队列的存储空间比 ...

  8. C语言基础学习基本数据类型-变量的输出与输入

    变量的输出 变量如何输入输出呢?实际上,在这之前你已经使用过输出语句(printf语句)了,我们可以使用printf来执行输出. printf语句的使用方法如下: printf(格式控制字符串, 数据 ...

  9. c语言基础学习06

    =============================================================================涉及到的知识点有:1.C语言库函数.字符输入函 ...

随机推荐

  1. tomcat跑多个项目和不同端口访问项目

    最近笔者在工作中需要同时运行多个项目,且有时需要不同端口访问项目:在此过程中,笔者觉得有必要将注意事项记录一下,以备后边查阅或广大读者借鉴. 工作环境是win7,64位,IDE为eclipse,浏览器 ...

  2. opencv中文网站相关下载

    http://wiki.opencv.org.cn/index.php/Download

  3. C++知识点总结(5)

    1.为何静态成员函数不能调用非静态成员函数 静态成员函数可以不需要类的实例就直接使用,非静态的成员函数很可能用到一些成员变量,而成员变量的创建和初始化是在创建了类的实例时在构造函数调用的时候才进行的. ...

  4. sql 一些偶尔会用到的写法和函数 不定时更新

    小数转整数: --round() 遵循四舍五入把原值转化为指定小数位数,如: ) -- =1 ) -- =2 --floor() 向下舍入为指定小数位数 如: SELECT floor(1.45) - ...

  5. java中静态方法和非静态方法调用的一点小困扰,已解决。

    public static void main(String[] args) { // TODO Auto-generated method stub SimpleGui1B gui=new Simp ...

  6. SSH (Struts2+Spring3.0+Hibernate3)框架(二) 框架的配置

    一.准备工作: 1. JDK -> jdk1.6.0_17 安装(环境变量配置): JAVA_HOME = C:\ jdk1.6.0_17; PATH = %JAVA_HOME%\bin; %J ...

  7. python使用基础(win10)

    1.安装 官网下载:https://www.python.org/ 请选择2.X版本 2.从命令提示符打开python 直接输入python点enter即可 查看python版本输入python -V ...

  8. 《Spring实战》-1

    1.Spring的主要特性:依赖注入DI和面向切面编程AOP. 2.关键策略: 轻量级和最小侵入性编程:POJO 松耦合:DI和AOP 声明式编程:切面和惯例 减少样板式代码:切面和模板 3.Spri ...

  9. [转]Oracle截取字符串相关函数

    转至:http://www.cnblogs.com/qmfsun/p/4493918.html 1.instr(sourceString,destString,start,appearPosition ...

  10. Java 在本地开发环境部署多个 spring 项目

    修改Tomcat 的 server.xml 文件 路径:C:\JAVA\apache_tomcat_8.5.11\conf\server.xml : 每个web项目的端口号不同,且存储的目录相同但是文 ...