关于printf和scanf函数是怎么工作的

时间:2022-03-25 06:02:35

#include <stdio.h>

int main(void)

{

printf("helloword!\n");

return 0;

}


#include <stdio.h>

int main(void)

{

int  a, b;

int sum = 0;

printf("Please input tow integer:");

scanf("%d%d", &a, &b);

sum = a + b:

printf("sum  = %d\n ", sum);

return 0;

}

相信很多人的第一次写程序都写过这两个程序,第一个程序“helloword”, 第二个程序输入两个整数输出它们之和,这两个程序分别用了了printf()和scanf()这两个标准输出输入函数,很多人都用过这两个函数,但是对于它们的用法却是一知半解,所以会经常写出这样的的程序,printf(“你输入的数是:%d”),scanf("%d", a)。很明显这两个函数是错误的,下面我们来认识一下这两个函数是怎么工作的。

一、printf()

1、printf()是格式化输出函数, 一般用于向标准输出设备按规定格式输出信息,调用格式为: printf("<格式化字符串>", <参量表>)。

我们看看它的函数原型为int printf(const char *format, ...);很多人不解,为什么printf()后面是三个点省略号呢?问得好!因为printf()函数是一个变参函数,它的参数的个数是可以变的,也就是说printf("a=%d\t b=%d\n", a, b);和printf("a=%d\t b=%d\t c=%d\n", a, b, c);都是合法的(前者两个参数,后者三个参数), 在标准IO库里面有很多这样的函数,有兴趣的可以去看一下。

2、printf()函数是行缓冲函数

这是什么意思呢?我们通过一段代码看看就知道了。

#include <stdio.h>

int main(void)

{

printf("这是我的第一个程序");

while(1);

return 0;

}

大家期待的结果是什么呢?打印出"这是我的第一个程序"这一句换?很遗憾!结果是什么都没打印。这就是因为printf()是行缓冲函数的原因,细心的读者就会发现上述的例子printf()这个函数没有加回车符'\n',printf()打印字符串是以回车符'\n'为结束符号的,没有回车符,并且程序还没有运行结束,那printf()函数就不会将字符串打印出来,所以以后使用printf()函数的时候别忘了加回车符'\n',很显然,去掉while(1);这段语句也能达到我们预期的效果,但不建议这样做,容易出错。

额外:下面我们补充一下缓冲区

缓冲区的类型
缓冲区 分为三种类型:全缓冲、行缓冲和不带缓冲。
1、全缓冲
在这种情况下,当填满标准I/O缓存后才进行实际I/O操作。全缓冲的典型代表是对磁盘文件的读写。
2、行缓冲
在这种情况下,当在输入和输出中遇到换行符时,执行真正的I/O操作。这时,我们输入的字符先存放在缓冲区,等按下回车键换行时才进行实际的I/O操作。典型代表是键盘输入数据。
3、不带缓冲
也就是不进行缓冲,标准出错情况stderr是典型代表,这使得出错信息可以直接尽快地显示出来。
缓冲区的刷新
下列情况会引发缓冲区的刷新:
1、缓冲区满时;
2、执行flush语句;
3、执行endl语句;
4、关闭文件。也即是程序运行结束。

printf()函数就是将缓冲区里面的数据打印到屏幕等输出设备上。

二、scanf()

1、scanf()函数的定义

scanf()是格式化输入函数与printf函数一样,都被定义在标准io库头文件stdio.h里,因此在使用scanf函数时要加上#include <stdio.h>

它的调用形式为: scanf("<格式说明字符串>",<变量地址>);变量地址要求有效,并且与格式说明的次序一致。我们来看看它的函数原型:int scanf(const char *format, ...);

同样的,scanf()函数也是一个变参函数。

2、scanf()是行缓冲函数

scanf()函数的工作原理如图所示:

关于printf和scanf函数是怎么工作的

32位计算机的寻址范围是2^32 = 4G,也就是说32位计算机最大支持4G内存,这里说的是虚拟内存,与真实内存大小没有关系,内核空间占1G,用户空间占3G,当我们从键盘输入一个字符时,系统首先将其放入内核空间的缓冲区,然后再从内核空间的缓冲区取出来放入到用户空间的缓冲区,当我们调用scanf()函数时,scanf()函数会从缓冲区取走符合它要求的数据,比如scanf("%d", &a),a是一个整型数据,当你键盘输入'c'时,'c'显然不符合scanf()函数的要求,它的要求是整型数据,而不是字符型数据,这是scanf()不会取走'c',返回0,即没有取到值,'c'会留在缓冲区,这也是我们为什么使用scanf()函数的时候,一般都要加一条清除缓冲区数据的语句while(getchar() != '\n');如果你键盘输入1的话,scanf()函数会将1从用户空间取出来,放入到变量a所对应的内存中,也即是a= 1,这时scanf()函数返回值是1。所以scanf()函数后面的参数a千万别忘了加取址符号“&”,不然scanf()函数就没法将用户缓冲区中数据放入到参数a的地址中,避免出现scanf("%d", a)这样的低级错误。记住一点:scanf()函数只是取走缓冲区符合它要求的数据,不符合要求的数据不会取走的,下次输入新的数据之前一定要先清除以前不符合要求的数据,这是一个很好的习惯。


当然上面我们讲的只是printf和scanf最基础的东西,它们还有很多用法,以及功能更加强大的变种,如fprintf(), sprintf(), sscanf(), fscanf()等等,想深入了解请去阅读相关资料,这是我第一次写博客,写得不好请大家多多包涵,如有错误的地方也请大家指出,谢谢大家了!一起进步!