包含
scanf和printf函数(标准输入输出函数),是C语言中最为常见的输入输出函数,在使用前,需要引用<stdio,h>这个头文件,这是因为scanf和printf函数包含在标准输入输出函数头文件<stdio.h>(Standard Input&Output),但由于其被使用得十分频繁,所以为了方便,许多头文件都会直接或间接地包含<stdio.h>这个头文件,举个例子,
#include<math.h>
int main() {
int a = 0;
scanf("%d ", &a);
printf("%d\n", a);
}
//未包含<stdio.h>头文件,且<math.hh>头文件中未直接或间接包含<stdio.h>头文件,程序报错;
下面是VS2022环境下的报错信息,表示scanf和printf函数未定义
但是,改变其头文件,将代码改为如下:
#include<iostream>
int main() {
int a = 0;
printf("%d", a);
}
代码成功运行,在屏幕上打印0;
这里虽然没有包含头文件<stdio.h>,但是头文件里面间接包含了<stdio.h>,我们可以鼠标右击头文件,转到文档,然后再重复上述操作,依次转到<istream>、<ostream>、<xlocnum>、<cstdio>文档的第12行,就能看到 #include<stdio.h>,这就属于间接包含头文件。
scanf函数
1)作用
从缓冲区中读取数据。大家在对scanf函数认识的时候,普遍会对scanf函数有一个误解,认为scanf函数是从键盘读取数据,然后储存到相应的内存空间中,实则这种认识与事实有一定偏差;
用户键盘上输入的所有数据会暂时储存在计算机中一块区域内,叫做缓冲区,**而scanf函数的作用正是从缓冲区内根据指定的输入格式取出所需的数据并储存在对应的内存中;**下面,我们可以用VS2022来直观地理解此过程:
#include<iostream>
int main() {
int a = 0, b = 0;
scanf("%d", &a);
printf("%d\n", a);
scanf("%d", &b);
printf("%d\n", b);
}
比如说上面这段代码,我们按“F11”逐步运行到第一个scanf函数,这里需要我们键入一个整数,但是这里我们键入两个整数:
继续往下走,我们打印a的值,根据打印结果与监视窗口,我们可以发现,只有a中的值变成了3,b的值并未发生改变,我们继续执行下一步:
在这一步,我们并未键入数据,但是我们发现,5储存进了b里面,最终我们打印b的值,为5:
2)参数
scanf的参数分为两部分,一部分是格式说明符,放于双引号内,用于控制读入数据的格式,另一部分参数是地址,表示读入数据存放的空间位置,其中格式说明符和地址都可以有多个,但是要注意,地址参数个数必须大于等于格式说明符参数个数,否则会出现以下错误,程序崩溃:
(1-1)格式说明符
顾名思义,起着限制读入数据的格式的作用,读取格式说明符与数据储存地址类型必须相匹配,否则读取失败,比如说%d,限定读入的数为整型数字,不能为除整型外的数据:
以下是常用的scanf格式说明符:
格式说明符 | 限定内容 |
---|---|
i | 表示读入整数,若前面带0,则表示八进制,0x表示十六进制,什么都不写表示十进制 |
d/u | 表示十进制整型数字,常用d |
o | 表示读入一个八进制整型数字 |
x | 表示读入一个十六进制整型数字 |
f/g/e/a | 表示读入一个十进制浮点数,常用f |
c | 表示读入一个字符 |
s | 表示读入一个字符串 |
p | 表示读入一个地址 |
几个常见的scanf函数使用误区:
(1)如果格式说明符与储存位置的数据类型不匹配,则读取的值不会是目标读取数值,且会消耗缓冲区的数据(其实质是能够正确读取缓冲区的数据,但是由于不同数据类型存储方式的差异,使实际存储的数据往往不是我们期望的数据);
(2)最终存储的数据了类型只与存储空间的类型有关,而与键入的数类型无关,
例如:
误区(1)说明
在代码38行,键盘格式说明符要求读入一个浮点数存放在a中,但是a储存数据类型为int型,我们在监视窗口可以看到a中存储的值并非我们想要的结果。
误区(2)说明
后续对b赋值时,格式说明符限定读取数据类型为浮点型,我们键盘键入6,从监视窗口可以看到,6被自动转为6.0000存储,而对c赋值时,键盘键入3.14,3.14被自动转为3存储。
(3)在格式说明符之间可以加上字符作为自定义分隔符,默认分割符为空格,在读入数据时,系统会根据分隔符将数据截取成多段,例如在两个百分号之间设置分隔符为’|‘,则在键盘输入的时候,需用’|‘将数据分开,否则函数未检测到分隔符,就不会继续往后读取,后面的数据留在缓存区中,例如以下代码:
int main() {
int a = 0, b = 0;
printf("第一次输入:");
scanf("%d|%d", &a, &b);
printf("%d %d\n", a, b);
scanf("%d|%d", &a, &b);
printf("%d %d\n", a, b);
printf("第二次输入:");
scanf("%d|%d", &a, &b);
printf("%d %d\n", a, b);
}
第一次输入时,用空格将两个数分开,在第一次读取中,只有a读取成功,下一次读取时,a读取到上次键盘输入的4,第二次输入,用规定分隔符将两个数据分开,a和b都成功读取;
(1-2)地址参数
地址参数表示读入的数据的存储位置,因为其本质是地址,所以需要使用取地址符“&”+已定义变量名或者直接放变量指针,地址参数与格式说明符按顺序一一对应,且数量不得少于前者,若地址参数个数大于格式说明符参数,则多余的参数将被忽略;
3)返回值
scanf函数的返回值为int类型,若读取成功,则返回成功读取的数据个数(最小可为0),若读取失败,则返回EOF,其默认值为-1;
#include<stdio.h>
int main() {
int a = 0,b=0,c=0;
printf("输出第一次测试返回值:%d\n", scanf(""));
printf("输出第二次测试返回值:%d\n", scanf("%d", &a));
printf("输出第三次测试返回值:%d\n", scanf("%d %d", &a,&b));
printf("输出第四次测试返回值:%d\n", scanf("%d %d %d", &a,&b,&c));
if (!scanf("%d", &a) != EOF)
{
printf("EOF\n");
}
printf("EOF=%d", EOF);
}
运行结果:
说明:第一次,未读入数据,打印返回值为0,第二次读入数据个数为1,打印返回值为1,在if处,键入ctrl+D+回车,结束当前读取,此时scanf还未读取到数据,故算为读取失败,返回值为EOF,打印EOF的值为-1,这是因为<stdio.h>头文件设定EOF=-1;
本期分享就到这里,后面小杨也会继续跟大家分享一些自己的学习心得体会,总结学到的知识点。
学习编程的路很长,小杨还在路上,希望看到这条博客的同学们能在学习的道路上越走越远,学有所成,小杨在与大家的分享中也能有所收获!