您的位置:首页 > 编程语言 > C语言/C++

[黑马程序员]01 [c语言][重要的知识点]printf函数和scanf函数的数据输出与读取问题

2015-04-09 00:28 441 查看
-------
android培训、java培训IOS培训、期待与您交流! ----------

这是刚学习C语言的时候遇到的最早的一个问题,是以前从来没有接触过的一个全新知识点,在这里作为博客日志记下

来,方便以后翻阅.

绪论

我们知道,在c语言编程中,printf函数是其标准函数库stdio.h中的标准输出函数,scanf函数是其标准数据库stdio.h中的标

准输入函数

printf函数的基本语法是: printf(“格式化字符串”[,参数,参数…]);

其功能就是打印格式化字符串

scanf函数的基本语法是:scanf(“格式化字符串”,变量的地址);

其功能是允许用户输入数据,并将数据赋值给变量

scanf函数和printf函数在c语言中使用频度极其之高,语法调用极其简单,即使是没有任何编程基础的人在敲了两遍之后

也能熟悉并运用scanf和printf函数实现简单地获得用户的输入并将其打印到屏幕上的功能.

那么scanf函数和printf函数具体是如何实现数据读取与数据输出的呢,一般来说作为软件端的编程者并不太需要了解硬

件式的实现机制,但是往往不了解一些具体实现机制,我们很容易出现错误.

下面就以我前段时间的一道练习题为例来分析scanf函数和printf函数的具体数据处理方式,以及我们为什么要分析弄懂

这个:

#include
<stdio.h>

int main(int argc,constchar * argv[]) {

//
有些时候输入一些东西
//
简单计算器
// 1输入数字
// 2输入运算符
// 3输入数字

int num1, num2;
// 两个整数变量,用于接收数字
char oper, temp;
// 字符变量,用于接收运算符

printf("请输入数字:");
scanf("%d", &num1);

//
循环中和掉所有的回车
scanf("%c", &temp);

printf("请输入运算符:");
scanf("%c", &oper);

printf("请输入数字:");
scanf("%d", &num2);
scanf("%c", &temp);

// ...

printf("num1 = |%d|\noper =|%c|\nnum2 = |%d|\n", num1, oper, num2);

return
0;
}

如上面的代码所示,我们需要实现一个简单计算器功能,由用户依次输入第一个操作数,运算符,第二个操作数,我们需要用

代码实现其计算功能并输出结果

我们的第一想法是:

在主函数main中,

首先申明需要接受的三个变量:

int num1, num2;
char oper;

然后利用printf,scanf函数交替的方式让提醒用户输入我们需要的三个变量:
printf("请输入第一个数字:");
scanf("%d", &num1);

printf("请输入运算符:");
scanf("%c", &oper);

printf("请输入数字:");
scanf("%d", &num2);

然后利用三个接受到得变量在代码内实现运算并由printf函数进行结果输出

然而在编译运行后进行输出的时候,我们遇到了问题,当我们在编译结果面板输入连续的数据时,我们习惯用空格或者回

车来分割我们输入的数据,当这里输入”1+1”时,我们得到的我们程序代码想要获得的结果,然而当我们尝试输入”1回车

+回车1回车”时,当输入+号并敲击回车时,代码就已经跳出等待输入直接结束了,程序本身并没有报错,那么这是为什么

呢?

这也就是为什么我们需要在这里讨论关于printf和scanf这两个看似简单的基本函数库函数的数据读取与输入问题

我们先来了解一下printf函数的数据打印过程:



如图所示,printf函数本身并不具有调用硬件操作硬件的功能,具体的硬件操作与软件编码的对接,是由操作系统来实现的,

操作系统有一个软件应用接口,对于printf函数,有一个专门的缓冲区,每次只有当缓冲区满地时候才会将结果显示到屏幕

中,如果手动的提供\n表示自动结束缓冲区,就可以将结果打印出来.

而对于scanf函数的数据读取,也要涉及到这个数据缓冲区,scanf函数的数据读取过程是这样的:

scanf(.....) {

从缓存中获取数据

如果没有数据

调用阻塞的函数,等到用户输入,在从缓存中取数据

拿到数据后将数据与格式化字符串比较

获得的字符 =将匹配到的字符从缓存中取出

如果格式字符串是%d

那么就调用转换的函数,将字符串转换成数字

赋值给地址指向的变量

否则,如果格式字符串%c

那么直接将数据赋值给地址表示的变量

否则, ... %f
... %s
...
}

弄清了上面缓冲区的概念以及printf函数与scanf函数对于缓冲区数据的处理方式,我们就能够分析上面例题出错的原因,

并对上面例题的逻辑语法结构进行修正和改善了

在上面的例题中,当我们按第一种敲入”1+1回车”,输入完敲击回车时,printf函数在接收到回车符的时候,会判定用户输入

结束,将”1+1回车”这4个数据传入缓冲区,我们的scanf函数是可以对缓冲区实现实时读取的,因此在缓冲区出现数据的那

一刻,scanf函数开始数据读取与匹配,先读取1,与scanf (“%d”)进行匹配,+号不是int型数据,第一个scanf函数只读取1;1被

取走,第二个scanf函数从+号开始读取,%c与+号匹配,与1不匹配,取走+号,第三个scanf函数取走1,正是我们想要的数据

获取方式.

然而第二种输入方式则出现了问题.让我们按第二种敲入”1回车+回车1回车”时,第一个scanf函数获取1,然而到第二个

scanf函数读取%c型数据时,因为回车本身为’\n’,也是一个字符,因此第二个scanf函数读取的是’\n’而不是+号,第三个

scanf函数需要读取的是int型数据,而这时剩下的数据是”+回车1回车”,+号不是int型数据,匹配失败,第三个scanf退出,这

时程序的读取就已经结束了,但是这时屏幕并没有输出任何结果,直到敲下+号后的回车,这时函数才判断输入结束,输出

结果

经过上面的综合分析,我们就知道了到底是哪儿出的错,以及为什么出错,那么怎么修改呢,第一种输入并不符合我们的输

入习惯,我们想要按第二种方式输入,那么代码该怎样修改?

在这里,出错的原因在于每次输入后的回车符,我们引入一个新的字符型变量char temp来截获掉这个回车符就行了.在每

一次scanf获取数据后,加上一个scanf(“%c”,temp);这样就把’\n’截获并过滤掉了,从而实现了第二种方式输入的数据获取

scanf函数另外有一点需要注意的是scanf在数据输入的时候会自动忽略空白符,因此scanf(“%c\n”,c);这种读取方式是永

远不会结束的.

经过以上对printf和scanf函数的缓冲区数据读取打印分析,我们对这两个函数的具体实现流程有了更深的了解,并且随之

发散的思想是,在今后的学习过程中对函数的实现机制的具体实现的了解,也是很重要的.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: