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

------- 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

 

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函数的数据打印过程:

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

如图所示,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函数的缓冲区数据读取打印分析,我们对这两个函数的具体实现流程有了更深的了解,并且随之


发散的思想是,在今后的学习过程中对函数的实现机制的具体实现的了解,也是很重要的.


你可能感兴趣的:(笔记日志)