scanf函数

  上一节中我们讨论了,如何将整数,浮点数,字符串打印到屏幕上去。既然有输出,怎么能没有输入呢?这一节中,我们来介绍与printf相反的scanf函数。

  scanf的功能是将键盘输入的字符串转换成整数、浮点数、字符或字符串。

1. scanf函数的使用公式

  1. scanf是一个变参函数。(参数的数量和类型不确定)
  2. scanf的第一个参数是字符串。
  3. scanf的第一个参数是需要输入的字符串以及需要被读取的占位符。
  4. scanf的后续参数,是依次被读取并赋值的变量地址。
  5. 占位符的类型和数量需要与后续的参数类型和数量对应。
#include <stdio.h>
int main()
{short s;int n;long l;float f;double df;scanf("s=%hd n=%d l=%ld f=%f df=%lf", &s, &n, &l, &f, &df);printf("%d %d %d %f %f\n", s, n, l, f, df);return 0;
}

  这里读者不必理解如何使用指针,只需要记住以下两条简单的规则:

  1. 如果用scanf()读取基本变量类型的值,在变量名前加一个&。
  2. 如果用scanf()把字符串去读到字符数组中,不要使用&。

  可以发现scanf是printf的逆向过程。注意,键盘输入的时候,必须要和scanf的第一个参数的字符串对应。也就是说,对于上面的代码输入必须是:

s=1 n=2 l=3 f=4.5 df=6.7

  以下几个是错误的示范

1 2 3 4.5 6.7
不一致,错误
s=1n=2l=3f=4.5df=6.7
由于scanf的第一个参数是"s=%hd n=%d l=%ld f=%f df=%lf",带有空格。
输入漏掉了空格,错误。
当然,如果scanf的第一个参数是"s=%hdn=%dl=%ldf=%fdf=%lf",那么这样就是正确的。
s=1,n=2,l=3,f=4.5,df=6.7
错误,由于scanf的第一个参数是用空格分隔的。

  视频演示

https://cpl.zhoushengjie.com/11_scanf/


TIPS:

  如果你使用的是较新版本的Visual Studio,scanf这类函数会被认为是不安全的,编译器会抛出C4996错误,并建议你使用别的安全函数替代。

  但是,目前我们并不想引入并讨论这一类安全函数。请将_CRT_SECURE_NO_WARNINGS加入预定义字符串,屏蔽不安全函数错误。

  添加步骤方式如下:

  1. 解决方案下,工程点右键,进入属性。
  2. 展开C/C++,选择预处理器。
  3. 点击预处理器定义【编辑】。
  4. 将_CRT_SECURE_NO_WARNINGS加入预处理定义。

  视频演示

https://cpl.zhoushengjie.com/11_scanf/


2. 占位符

  scanf的占位符规范和printf类似,但有些不同。请使用的时候,不要混淆了。scanf的占位符组成如下。

  1. 一个可选的最大字段宽度,用一个正的十进制整数表示。
  2. 一个可选的长度指定符
  3. 必须的转换操作。
转换操作 长度指定符 参数类型
d hh char *
d h short int *
d int *
d l long *
d ll long long *
u hh unsigned char *
u h unsigned short int *
u unsigned int *
u l unsigned long *
u ll unsigned long long *
f float *
f l double *
f L long double *
c char *
s char *

3. 示例

    short s;scanf("%hd", &s);int n;scanf("%d", &n);long l;scanf("%ld", &l);long long ll;scanf("%lld", &ll);
    unsigned short us;scanf("%hu", &us);unsigned int un;scanf("%u", &un);unsigned long ul;scanf("%lu", &ul);unsigned long long ull;scanf("%llu", &ull);
    float f;scanf("%f", &f);double df;scanf("%lf", &df);long double ldf;scanf("%Lf", &ldf);

4.scanf与printf的不同

  1. printf的后续参数不要加&,而scanf由于需要一个指针,所以需要加&。

  2. printf的参数由于比int小的变量会升级为int,这样数据仍然是完整的。仅比int大的需要额外指明长度指示符。

  3. scanf会将数据填充到对应的变量里去,必须指明被填充的对象是什么,用int来填充char很显然是错误的,所以必须明确指定长度指示符。例如%hhd用于char,%hd用于short。

5. 检查是否使用了错误的占位符

  如果你使用了错误的占位符,得益于新版的编译器,你可以在warning中看到这些提示。

#include <stdio.h>
int main()
{char c;scanf("%d", &c);short s;scanf("%d", &s);int n;scanf("%d", &n);long l;scanf("%d", &l);long long ll;scanf("%d", &ll);return 0;
}

  根据提示,更正为如下即可。

#include <stdio.h>
int main()
{char c;scanf("%hhd", &c);short s;scanf("%hd", &s);int n;scanf("%d", &n);long l;scanf("%ld", &l);long long ll;scanf("%lld", &ll);return 0;
}

6. scanf参数必须用&的原因

void setToZero(int a, int b)
{a = 0;b = 0;//  当函数不需要返回值的时候,可以把返回值类型设置为void
}int main()
{int a, b;a = 2;b = 3;setToZero(a, b);printf("%d %d\n", a, b);return 0;
}

  在这段代码中,变量a,b分别在main,和add变量中,那么,main中的a和b与add中的a和b是同一个变量吗?

  显然不是,函数调用的时候,是把main中a,b的值,传递给了add中的a,b。
add中无论如何修改a,b。无法影响到main中的a,b。这里有个技巧,{}是变量作用域,在不同{}内的同名变量,是不相干的。

  既然不管是否同名,用传递值的办法setToZero都无法影响main中的变量。

  那么回到scanf中,它也无法影响到scanf外的变量,那是怎样修改scanf外面的变量的呢?

  答案是,使用指针。指针就是一个变量的地址,有了这个地址就能找到这个变量,并且修改它的值。因此,scanf的参数,都用了&。传递的类型,都是指针类型。

C语言中scanf函数详解相关推荐

  1. C语言中get_put函数详解,C语言第五课之getchar函数和putchar函数

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 getchar函数也就是键盘输入函数,这个函数和scanf函数不一样!getchar函数没有scanf函数灵活.下面就给大家介绍下getchar函数的介绍 ...

  2. C语言中memset函数详解(很清晰易懂)

    功 能: 将s所指向的某一块内存中的每个字节的内容全部设置为ch指定的ASCII值, 块的大小由第三个参数指定,这个函数通常为新申请的内存做初始化工作 用 法: void *memset(void * ...

  3. c语言中strtok函数详解,手把手教你自主实现字符串切割函数,内附详细代码。

    函数功能简介: 对字符串str进行切割,切割的标志为字符指针q指向的这两个字符 "# *":. 但是在对这个函数进行调用时,只有在第一次调用时,才会将str这个字符串的首地址传递过 ...

  4. C语言中memset函数详解

    功 能: 将s所指向的某一块内存中的每个字节的内容全部设置为ch指定的ASCII值, 块的大小由第三个参数指定,这个函数通常为新申请的内存做初始化工作 用 法: void *memset(void * ...

  5. c语言函数time用法,c语言中time函数详解

    总结: time_t time(time_t *timer); 返回以格林尼治时间(GMT)为标准,从1970年1月1日00:00:00到此刻的本地时间所经过的秒数,time_t实际是个long长整型 ...

  6. C语言中string函数详解

    linux kernel code :  kernel/lib/string.c strsep,strtok,strchr ,strstr ...... PS:本文包含了大部分strings函数的说明 ...

  7. C语言中get_put函数详解,C++ get()和put()读写文件详解

    在某些特殊的场景中,我们可能需要逐个读取文件中存储的字符,或者逐个将字符存储到文件中.这种情况下,就可以调用 get() 和 put() 成员方法实现. C++ ostream::put()成员方法 ...

  8. java 函数fun_c语言中fun用法详解_后端开发

    Java Dao层的作用_后端开发 Dao层叫数据访问层,属于一种比较底层,比较基础的操作,可以具体到对于某个表或某个实体的增删改查,其Dao层的作用是对数据库的访问进行封装,从而不涉及业务,实现解耦 ...

  9. c语言中funx的作用,c语言中fun用法详解

    C语言中fun用法详解 fun函数是自定义的C/C++语言函数,函数功能多样.该函数名为"函数"英文function的简写,一般在示例和试题中使用,通常在主函数中被调用. C/C+ ...

最新文章

  1. boost之asio异步io使用实例
  2. NSA-LDL论文修改建议20211026BRT
  3. 如何使用router-link对象方式传递参数?
  4. vsftp pam mysql_实验记录:vsftp整合mysql-pam管理虚拟账号
  5. 美国空军学习编程,为五角大楼节省了上百万!
  6. 《众妙之门——用户体验设计的秘密》一2.3 触摸至上的设计
  7. php 数组 闭包,PHP如何用array_filter加闭包函数过滤数组?
  8. Echarts 下载使用教程
  9. matlab矩阵运算rank,Matlab矩阵运算
  10. oracle11g怎么打开oem,oracle11g启动OEM
  11. EDEM资料大全(包含教程、论文、案例、应用)
  12. Java多线程的简介
  13. 命令提示符命令(cmd)
  14. Double转BigDecimal并保留两位小数出现异常: java.lang.ArithmeticException: Rounding necessary
  15. 量化投资学习——关于XTP交易柜台
  16. HashMap与HashSet
  17. vr全景技术开启智能化vr酒店宣传新模式
  18. 2019高考江苏卷语文作文
  19. 牛客网-SQL题库笔记
  20. 点阵---点亮一个点(内含硬件设计+软件编程+思路)

热门文章

  1. supermicro服务器系统,Supermicro发布新一代1.6GHz系统总线服务器工作...
  2. “超龄儿童硬要过六一”,测试工程师自救指南!
  3. ROS话题模式及多线程
  4. XPath:爬取百度贴吧图片,并保存本地
  5. OC底层原理-alloc流程
  6. 男人付帐的目的和女人付帐的原因经典啊
  7. Android自定义视频播放器(一)
  8. 原来 goim 是这样实现高并发
  9. 1天考3科、机考、2科,今年二建考试有哪些新变化?
  10. threejs通过模型名称获取模型,并修改颜色