介绍
首先我们看一下scanf的声明, int scanf ( const char * format, ... );我们可以由此得出scanf的返回值是整型,形参是指针即地址。下面我们看一段代码。
#include <stdio.h>
int main()
{
int a=0;
scanf("%d",a);
printf("%d",a);
return 0;
}
如果运行这段代码,他会报错。这是新手十分容易出错的地方,scanf("%d",a)中a是变量不是地址,所以会报错。改也十分简单,只要加上&(取地址操作符)便可以。
#include <stdio.h>
int main()
{
int a=0;
scanf("%d",&a);
printf("%d",a);
return 0;
}
返回值
接下来我们先看scanf返回值有什么意义。
如果scanf函数成功执行,该函数返回已成功填充的参数列表的项数。此计数可以与预期的项目数匹配,也可以由于匹配失败、读取错误或文件末尾的到达而更少(甚至为零)。就是返回成功匹配占位符的个数。
如果scanf函数遇到文本末尾会返回EOF,EOF是一个宏,类似于NULL,EOF值一般为-1.
如果scanf在执行中出现错误,会返回已经成功匹配的个数。接下来我们看段代码。
空白字符
scanf函数将读取并忽略在下一个非空格字符之前遇到的任何空格字符(空格字符包括空格、换行符和制表符 。也就是scanf(“#%…… ” ,)(#表示空格)引号中空白字符会起到引起函数读取输入的数据。遇到空格字符会被忽略,直到遇到非空白字符。
接下来看一段有趣的代码。
代码似乎没有问题,但为什么输入3 4后按enter却不可以运行,直到输入10才可以正常运行呢?如果仔细观察我们可以发现在scanf("%d %d ", &a, &b);中第二个%d后面加了一个空格。这个空格会再次引起函数读取数据,认为后续还有数据要写入。我们多次按的enter其实属于空白字符,那么他不会遇到空白字符满足停下,会一直读取直到非空白字符即输入10等非空白字符。这个10由于没有对应格式控制字符不会被读取。
删除空格后便可按照我们意愿正常运行。
下面我们再看一个有趣的代码
#include <stdio.h>
#include<ctype.h>
int main()
{
char ch = 0;
while (scanf("%c\n", &ch) != EOF)
{
if (isalpha(ch))//isalpha库函数当ch是字母时返回1,否则返回0
{
printf("%c 是字母\n");
}
else
{
printf("%c 不是\n");
}
}
return 0;
}
想一想他的运行结果为什么??
我们会发现以上问题,原代码知道每次输入按enter后都会有\n,于是想再scanf中用”%c\n“的方式去除\n,但他想少了一步,那是\n是scanf中三大字符类中的空白字符!!!!这边造成了问题。
有以下两种改动方案
普通字符
在scanf中如果在引号内输入普通字符,即非格式控制字符与空白字符。任何不是空格字符(空白、换行符或制表符)或格式说明符(以 % 字符开头)的字符都会导致函数从缓存区中读取下一个字符,将其与此非空格字符进行比较,如果匹配,则将其丢弃,函数继续使用格式的下一个字符。如果字符不匹配,则函数将失败,不在继续读取数据。
我们看下述代码
这是一个简单的加法运算,但结果却是4+3=4,这显然有问题,但问题在哪里呢?
我们仔细观察,发现scanf("%d,%d", &a, &b);中有个逗号,会不会是他影响的呢?我们逐步分析,首先第一个%d引起读取数字4,没有问题,逗号引起函数从缓存区中读取字符空格被忽略,到3,字符逗号与3不相同读取错误,函数结束,此时b还是初始化的0,并没有被写入3,故a+b=4.是不是恍然大悟。直到错误后我们有一下两种该法
接下来是我们scanf的核心,格式控制字符。
格式控制字符
由初始百分号 (%) 组成的序列表示格式说明符,该说明符用于指定要从缓存区中检索并存储到附加参数所指向的位置的数据的类型和格式。
其一般格式为 %[*][width][length]specifier
其中[]内的是可选输入,按照需求自定义添加。
specifier类型
在这张表中我们常用的有d,f,c,s,p,o,x。调用方法也十分简单,scanf("%d", &a);引号中用%开始加类型,记得格式字符类型要和后面写入数据是同一类型。
%c注意事项
其中要注意的是%c是输入字符,一定记得空格字符也属于字符,也会被读取。下面我们看个例子。
这是为什么呢?原因很简单,b里面被写入的是空格,而不是w,b也输出了不过输出空格看不见。我们可以通过调试观察这一神奇的过程。
我们知道字符在内存中其实以ASCII值来储存,下面是我截取部份表
我们可以看出32其实就是空格的ASCII值,对应换行,tap都有ASCII值,我们在输入字符时要而外注意这个问题。
%s注意事项
我们仔细看最开始表不难发现,scnaf(“%s”)结束条件是遇到空白字符,如果我们要输入一段话那么就会出现错误。例如下面代码。
原因很简单I后面便是空格,这种模式输入时遇到空格就结束。我们可以怎么改呢?
我们仔细想,一段话结束标志是不是在结尾有个换行符即\n,那么我们便可以这么改进代码。
除此之外,我们还有一种方法,我们仔细看最初的表会发现倒数第三个是否定扫描集,他的意思十分简单,从第一个字符开始读取,如果与[^c]内字符不一样继续读取,如果一样停止读取。我们便可以将上述代码在简化。
[*]
这个用于处理一段数据中不要的数据,例如2023/11/28中我们只要数字,/不要便可运用*
[width]
最大读取字符数目,这个对于字符串好理解,当为数字时,我们把它类似当于字符串来看。
[length]
也许有读者疑惑为什么类型中没有ld,lld,hd,lf等类型,其实他们都可以看为[length]加基本类型构成的。
当你加入长度后,后面地址的类型要与之对应。
美好的时光总是短暂,今天就到此结束了,欢迎大家来观摩指正。