scanf()函数的原理
最近使用scanf发现了自己对scanf函数还是不太了解,主要出现在无意中出现的一个错误;
scanf正确的写法是,scanf中以什么格式输入变量,则变量的类型就应该是什么格式,如下面scanf输入到变量的格式是%c形式,因此变量sum的类型必须是char型,要不存储到sum中的数值会出错;
注意:打印的时候是分别以%c、%d 的形式答应的
字符a的ASCII码值是97
char sum;
printf("请输入一个字符:");
scanf("%c", &sum);
printf("%c\n", sum);
printf("%d\n", sum);

如果将sum定义成int类型,但是scanf以%c的格式赋值给sum,会出现什么样的错误呢
int sum;
printf("请输入一个字符:");
scanf("%c", &sum);
printf("%c\n", sum);
printf("%d\n", sum);

看问题来了,为什么sum为int类型时;以%d输出时明显不对,%c输出却没有问题?
%c格式输出没有问题说明scanf以%c格式输入到sum的过程是没有问题的,出现问题的原因是scanf内部实现的原理没弄清楚
第一个首相想到,难道是一个字符/字符变量赋值给一个整形变量,再以%d形式打印时会出现这样的问题吗?
其实是不会的因为编译器会进行自动转换(隐式转换),但还是看一下这种情况是什么样子的
int sum;
char p;
p = 'a';
sum = p;
printf("%c\n", sum);
printf("%d\n", sum);

第二个猜测是,在scanf内部实现中以什么样的格式赋值给变量时,就会以此格式对应类型的内存大小赋值给变量且,如果变量原本所占内存比scanf中所用格式的内存大,则多出的那一部分会被填充为1(为什么会猜测填充为1呢? 主要是上面以%d输出是数值很大,并且为负值),下面写代码验证一下
int sum;
char *b;
b = (char *)∑
*b = 'a';
printf("%c\n", sum);
printf("%d\n", (char)sum);
printf("%d\n", sum);


看上面sum中的值61前面全是c,c在16进制中为1100,61表示97,所以在低地址值是正确的,但在高地址处被填充的1100;并且红色全出的数值和scanf出错的那部分相同,所以scanf中内部实现原理是和上面代码类似的。以char类型解释;
即scanf(“%c”, &sum)时;内部会将 &sum 强制转换成 (char *)类型,并且赋值给 char * 类型的变量b,然后用 *b 来接收输入的值,也就改变了 sum中的值,但因为char字节小于int字节数,所以多余的字节会被其它值填充。
再看看上面隐士转换情况多余的地址被填充了什么,为方便对照,再把代码写一遍;
int sum;
char p;
p = 'a';
sum = p;
printf("%c\n", sum);
printf("%d\n", sum);


隐士转换多余字节被填充为0;所以隐士转换不影响值(数值比较小时)的显示,但可能会字节数不相等会影响结果精度等。
scanf()函数的原理的更多相关文章
- scanf()函数原理
一.三点说明 1.用户输入的字符,会以ASCII码形式存储在键盘缓冲区:2.每调用一次scanf函数,就从键盘缓冲区读走一个字符,相当于清除缓冲区:3.若用户一次输入n个字符,则前n次调用scanf函 ...
- C语言可变参数函数实现原理
一.可变参数函数实现原理 C函数调用的栈结构: 可变参数函数的实现与函数调用的栈结构密切相关,正常情况下C的函数参数入栈规则为__stdcall, 它是从右到左的,即函数中的最右边的参数最先入栈. 本 ...
- c语言学习之基础知识点介绍(三):scanf函数
本节继续介绍c语言的基础知识点. scanf函数:用来接收用户输入的数据. 语法:scanf("格式化控制符",地址列表); 取地址要用到取地址符:&(shift+7) 例 ...
- C语言之可变参实现scanf函数
既然有printf函数可变参实现,那就一定有scanf函数的可变参实现.废话不多说,源码奉上: 本源码不过多分析,如要明白原理,请翻本博客以往的文章看说明. 欢迎关注新浪微博:http://weibo ...
- scanf函数的返回值
#include <stdio.h> int main() { ]; ]); printf("%d\n", n); ; } 此刻注意scanf函数里面的格式限定,该代码 ...
- C语言中scanf函数的实现
接上一篇C语言中可变参数函数实现原理,从理论上详细介绍了C语言中可变参数函数的实现,这一篇从minix内核源码中的scanf函数入手,学习C语言经典可变参数函数的实现过程 在scanf.c文件中,可以 ...
- 4-printf & scanf函数
一.printf函数 这是(printf和scanf)在stdio.h中声明的一个函数,因此使用前必须加入#include <stdio.h> 1.用法 1> printf(字符串) ...
- 【前端】require函数实现原理
// require函数实现原理: function require(modulePath) { var regExp = /\w+$/g; var moduleName = regExp.exec( ...
- C语言scanf函数详细解释
原文链接 函数名: scanf 功 能: 执行格式化输入 用 法: int scanf(char *format[,argument,...]); scanf()函数是通用终端格式化输入函数,它从标准 ...
随机推荐
- vue结合webpack打包问题
在使用vue开发项目时,如果要使用其单文件组件特性,必然要使用webpack或者其他打包工具打包,这里我用到的是webpack打包,首先是搭建vue环境和webpack环境,在这里遇到的一个问题是在成 ...
- 通过修改profile 来修改账号的过期时间
转至:https://blog.csdn.net/xxzhaobb/article/details/80026028 查看账号的过期时间 SYS@test>select username,exp ...
- linux 提权防护
linux 用户提权 利用系统漏洞或者程序等方面的缺陷使一个低权限用户,获得他们原本不具有的权限或者得到root权限 下面介绍几种可能得到root访问权限的方式 1, 内核开发 防护:及时更新补丁 臭 ...
- Java:代码改进技巧
1.类名首字母大写:方法名首字母小写:常量名全大写: 2.当控制语句只有一句时,可以省略大括号{}:但是,建议任何时候都保留大括号,因为这是Java语句块的标志 3.用某个接口承接实现类时(多态),之 ...
- JZ-062-二叉查找树的第 K 个结点
二叉查找树的第 K 个结点 题目描述 给定一棵二叉搜索树,请找出其中的第k小的结点. 题目链接: 二叉查找树的第 K 个结点 代码 /** * 标题:二叉查找树的第 K 个结点 * 题目描述 * 给定 ...
- 被vector动态扩容给坑了!
大家好,我是东北码农.记录一下工作中事. 前几天,运维同事给我反馈了一个问题: 通过监控发现,线上的一个服务,业务线程时不时会出现卡顿,卡顿大约持续几秒. 我们做金融系统后台开发的,对性能要求很严格的 ...
- 【一周聚焦】 联邦学习 arxiv 2.16-3.10
这是一个新开的每周六定期更新栏目,将本周arxiv上新出的联邦学习等感兴趣方向的文章进行总结.与之前精读文章不同,本栏目只会简要总结其研究内容.解决方法与效果.这篇作为栏目首发,可能不止本周内容(毕竟 ...
- java后端工程师学习路线
根据自己的经历和见识梳理了一份java后端工程师的学习路线(不含安卓方向),难免有局限性和疏漏,请在评论区反馈意见和建议! 很明显的是我的学习路线过于庞大了[尴尬],你可以认为这些只是我的一家之言,具 ...
- tep完整教程帮你突破pytest
持续维护的教程 tep教程会随着版本更新或经验积累,持续维护在电子书中,最新的最全的内容请锁定这篇文章[最新]tep完整教程帮你突破pytest: https://dongfanger.gitee.i ...
- Android 12(S) 图形显示系统 - 初识ANativeWindow/Surface/SurfaceControl(七)
题外话 "行百里者半九十",是说步行一百里路,走过九十里,只能算是走了一半.因为步行越接近目的地,走起来越困难.借指凡事到了接近成功,往往是最吃力.最艰难的时段.劝人做事贵在坚持, ...