学好这4点,scanf函数轻松拿下

您所在的位置:网站首页 scanf报错原因 学好这4点,scanf函数轻松拿下

学好这4点,scanf函数轻松拿下

2023-03-22 07:31| 来源: 网络整理| 查看: 265

scanf函数的介绍: 1.转换说明2.scanf函数的参数3.转换说明中的修饰符4.scanf函数的返回值 注:scanf函数的使用需要包含头文件 (注:本文中多次用到了printf函数,如果对printf函数还不够了解的小伙伴可转至: 还不会用printf函数?我来教你 进行学习)

1.转换说明

为什么我们要用到转换说明呢? 原因如下: 我们想从键盘输入各式各样的数据类型到程序中如:整数,浮点数,字符… 但是键盘只能输入字符例如:输入 3.14 有人认为这里输入的是数值3.14,但这想法并不对,从计算机层面的理解应该是输入了4个字符,分别是字符 ‘3’ 字符 ‘.’ 字符 ‘1’ 和字符 ‘4’ 我们要是把输入的 3.14 直接储存起来得到的应该是四个字符,而不是数值3.14。 那我们要怎么得到数值3.14呢?方法很简单——就是使用转换说明。 转换说明有很多,如下表:

转换说明含义%c把输入转换成字符%d,%i把输入转换成有符号十进制整数%e,%f,%g,%a,%E,%F,%G,%A把输入转换成浮点数(C99新增%a和%A)%o把输入转换成有符号八进制整数%u把输入转换成无符号十进制整数%x,%X把输入转换成有符号十六进制整数%p把输入转换成地址%s把输入转换成字符串

以上转换说明中的 %c 与其他转换说明有所不同: 其他转换说明会跳过所有的 空白(换行符,制表符,空格)字符,从第一个 非空白字符 开始读取,而 %c 则会从开始位置读取一个字符,无论字符是否为空白(换行符,制表符,空格)字符。 (注:%s从第一个非空白字符开始读取,读入下一个空白(换行符,制表符,空格)字符之前的所有字符且储存在指定地址处,并在读取的最后一个字符后补充一个字符‘\0’使其变成一个C类型的字符串。) 使用不同的转换说明会将我们从键盘输入的字符转换成不同数据类型的值, 例代码如下:

#include int main() { float a; int b; scanf("%f %d", &a, &b); printf("%.2f\n%d", a, b); return 0; }

结果如下: (注:第一行为输入,第二,三行为输出。)

在这里插入图片描述 可以看出:即使输入相同,但用不同的转换说明,得到的结果并不相同。 原因是:

%f是将与浮点数有关的字符全部读入,如遇到其他类型的字符则结束读入,随后将读入的字符转换成相应的值储存起来。 如:本例中的 “3.14” ,%f则是将其四个字符全部读入后转换成值的形式并储存到变量a中。而%d则是将数字字符全部读入(包括‘+’,‘-’号),如遇到非数字字符就结束读入,随后将读入的字符转换成相应的值储存起来。 如:本例中%d将字符 ‘3’ 读入后遇到字符 ‘.’ 便结束了读入,将读到的字符 ‘3’ 转换成值的形式并储存在变量b中。

所以打印时a的值是3.14,b的值是3。

(扩展:有人会疑问了,如果字符 ‘.’ 字符 ‘1’ 和字符 ‘4’ 没有被读入那么它们去哪了,其实它们被留在 “输入缓冲区” 中了,并且下一次的读取会从上一次读取结束的位置开始,即:从字符 ‘.’ 开始读取。所以如果后续使用%d读取则会读取失败,故有时的输入与转换说明不匹配时很容易出现bug,我们应尽量避免这种情况。) (注:有关 输入缓冲区 的知识读者可自行扩展,本文不作过多赘述。)

2.scanf函数的参数

scanf(格式化字符串,变量1的地址,变量2的地址,变量3的地址, …); scanf函数的参数包括格式化字符串和多个变量的地址。 转换说明应全部位于格式化字符串中,可以有多个转换说明,也可以只有一个。而读取的数据会通过传入的变量的地址储存在变量中。 (注:正常情况下一个转换说明应对应一个变量地址参数,即:转换说明数应和变量地址数相同。但如果转换说明含有 * 号则应特殊处理,详情见后文。)

3.转换说明中的修饰符 转换说明修饰符含义数字输入的最大字段宽度,如果没达到最大字段宽度之前遇到空白(换行符,制表符,空格)字符则提前停止读取h与%i,%d 结合表示转化为short int类型的值,如:%hd,%hi ;与%o,%x,%u 结合表示转换成unsigned short int类型的值,如:%ho,%hx,%hul与%i,%d 结合表示转化为long类型的值,如:%ld,%li ;与%o,%x,%u 结合表示转换成unsigned long类型的值,如:%lo,%lx,%luL与%e,%g,%f 结合表示转换成long double类型的值,如:%Le,%Lg,%Lfhh与 %u 结合表示转化为unsigned char类型的值,如:%hhu 与 %d 等 结合表示转化为signed char类型的值,如:%hhdll与 %u 结合表示转化为unsigned long long类型的值,如:%llu 与 %d 等 结合表示转化为long long类型的值,如:%lld (long long类型属于C99标准)*号阻止赋值,如:%*d

这里主要讲解一下修饰符 “数字” 和 “*号”:

数字 例代码如下: #include int main() { char arr1[10] = { 0 }; char arr2[10] = { 0 }; char arr3[10] = { 0 }; scanf("%s", arr1); scanf("%10s", arr2); scanf("%5s", arr3); printf("%s\n", arr1); printf("%s\n", arr2); printf("%s\n", arr3); return 0; }

结果如下: (注:第一行为输入,第二,三,四行为输出。)

在这里插入图片描述 可以看出:如果规定了输入的 最大字段宽度,则最多只会读取 最大字段宽度的字符,而且如果提前遇到了 空白(换行符,制表符,空格)字符则会直接结束读取。

*号 例代码(1)如下: #include int main() { int a; scanf("%d %*d %*d", &a); printf("%d", a); return 0; }

结果如下: 在这里插入图片描述 ————————————————————————————————————— 例代码(2)如下:

#include int main() { int a; scanf("%*d %d %*d", &a); printf("%d", a); return 0; }

结果如下: 在这里插入图片描述 ————————————————————————————————————— 例代码(3)如下:

#include int main() { int a; scanf("%*d %*d %d", &a); printf("%d", a); return 0; }

结果如下: 在这里插入图片描述 ————————————————————————————————————— 例代码(4)如下:

#include int main() { int a = 0, b = 0, c = 0; scanf("%*d %*d %d", &a, &b, &c); printf("%d %d %d", a, b, c); return 0; }

结果如下: 在这里插入图片描述

(注:以上四个结果均为第一行为输入,第二行为输出) 不难看出三个转换说明对应三个输入,但含有 *号 的转换说明不需要有对应的变量地址参数,更不会把所得值储存在变量中。 且第一个不含*号 的转换说明无论在格式化字符串中是第几个转换说明都对应变量地址列表的第一个参数。

4.scanf函数的返回值

scanf函数的返回值为成功读取的项数,如果读取到文件末尾则返回EOF。 (注:以下三个结果均为第一行为输入,第二行为输出) 例代码(1)如下:

#include int main() { int a = 0, b = 0, c = 0; c = scanf("%d %d", &a, &b); printf("%d %d %d", a, b, c); return 0; }

结果如下: 在这里插入图片描述 从代码(1)可知,当scanf函数成功读取两个值并储存到变量a,b中后,会返回成功读取的项数,即:2。 ————————————————————————————————————— 例代码(2)如下:

#include int main() { int a = 5, b = 5; b = scanf("%d", &a); printf("%d %d", a, b); return 0; }

结果如下: 在这里插入图片描述 从代码(2)可知,这里输入与转换说明不匹配,并没有成功读入值并储存到变量a中,故scanf函数返回0。 ————————————————————————————————————— 例代码(3)如下:

#include int main() { int a = 5, b = 5; b = scanf("%*d %d", &a); printf("%d %d", a, b); return 0; }

结果如下: 在这里插入图片描述 从代码(3)可知,*号的存在使得即使输入与转换说明匹配,也不会成功读入值,自然也不算成功读取项,故这里只返回1。

通过学习scanf函数的返回值,可以通过返回值实现多组数的读取。 例代码如下:

int a; while (scanf("%d", &a) == 1) { }

这里表示一直输入直至读取失败才退出while循环,可以在while循环中对每次成功读取的值进行操作从而实现多组数的读取。 以下版本也很常用:

int a; while (scanf("%d", &a) != EOF) { }

这里表示一直输入至读取到文件末尾的标志EOF时才退出while循环,这同样可以实现多组数的读取。

(扩展1:EOF(End Of File)表示文件结尾的标志,当scanf函数读取到文件的末尾时会返回EOF。) (易错:EOF的实质是在头文件中#define定义的宏常量,值通常为“-1”。并不是字符‘E’字符‘O’和字符‘F’的组合)

(扩展2:操作系统判断文件是否读到末尾的方法大致分为两种: 1.一种是在文件尾放入一个特殊的字符来标记文件的末尾,例如:在文件末尾内嵌一个Ctrl+Z,所以scanf函数在读取时读到Ctrl+Z时便会返回EOF,用以告知用户文件读取完毕。 内嵌一个Ctrl+Z这一操作一般由操作系统自动完成,不需要我们自行添加,且内嵌的Ctrl+Z我们在文本文件中看不到,但确是真实存在的。 这一方法的一个缺点在于:如果文件中保存有Ctrl+Z就会被误判断成读到了文件尾提前结束文件的读取。所以使用这种方法在保存文件时应尽量让文件中不含Ctrl+Z。 2.另一种就是利用文件储存大小的信息来标记文件末尾,例如:一个文件大小有5000字节,则scanf函数在文件中读完5000字节后返回EOF。 这种方法好处在于:文件中可以储存所有不同的字符。)

(扩展3:有人会疑问了,我们平时用的多数是键盘输入而不是文件输入,这种情况下我们又应该如何标记键盘输入的末尾来告知程序读取到输入的末尾了呢? 其实大部分的系统都有办法通过键盘模拟文件结尾的条件,不同系统的具体实现可能会有所不同,本文就不一一举例了,读者可自行了解。)

以上为scanf函数的一些基本用法,如果能够帮到你那就点赞关注收藏支持一下吧!



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3