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()函数是通用终端格式化输入函数,它从标准 ...
随机推荐
- spark submit local遇到路径hdfs的问题
有时候第一次执行 spark submit --master local[*] 单机模式的时候,可以对linux本地路径进行输出.但是有时候提交到yarn的时候,是自动加上hdfs的路径这没问题, 但 ...
- 解压jdk报错gzip: stdin: not in gzip format
0x00 报错截图 0x01 下载方式 下载地址是直接在oracle官网[复制链接地址]获得. 0x02 解决问题 查看一下下载的文件 发现下载下来的是HTML文件. 然后就去oracle官网抓包看了 ...
- qt(二)
主程序入口: #include <iostream> #include <QApplication> #include "MainWindow.h" int ...
- redis数据类型的使用及介绍
Redis数据类型 1.Sting类型 set命令 设置键值,存在则覆盖,不存在则新建 set key value EX 秒 设置有效时长为秒 nx 如果键不存在则新建,如果存在返回nil xx 只有 ...
- SQL Server--频繁建立连接和断开连接
使用数据库时,不建议一直与数据库保持连接,最好用时连接用完断开连接. 我的C#程序中采用"用时连接用完断开连接"的方式: 之前是C#程序调用本地数据库,没遇到问题: 后来改为C#程 ...
- ARP协议、路由器详细工作原理
ARP原理分析 第一次通信时,有对方IP地址但是没有目标MAC地址,该PC就会在网络层启动ARP协议生成一个ARP报文"我叫1.1,我的MAC是AA;谁是1.3,你的MAC是多少?" ...
- 【1024打卡】C++字符串的输出((c语言风格)
c++字符串输出(c语言风格) 文章目录 c++字符串输出(c语言风格) 杂记 代码 杂记 今天程序设计竞赛白给了,果然还是太弱了,y总带带我TAT ┭┮﹏┭┮1024快乐 代码 c语言学习 #inc ...
- centos根目录扩容
一.扫描磁盘 若已在虚拟机增加了磁盘且没看到磁盘 运行下面的命令来查找系统中所有的主机总线编号: # ls /sys/class/scsi_host 得到主机总线编号后,运行以下命令来发现新的磁盘: ...
- 集合 copy
#集合的创建 # set = set(["barry",1,2]) # print(set) # set1 = {1,2,3} #集合的增 # set1 = {'alex','wu ...
- 修改vue的url
1.修改router的index.js文件,增加base url的配置 2.修改config的index.js文件. bulid的index,assetsRoots和assetsPublicPath的 ...