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()函数是通用终端格式化输入函数,它从标准 ...
随机推荐
- 用 UI 多线程处理 WPF 大量渲染的解决方案
众所周知, WPF 的 UI 渲染是单线程的,所以如果我们异步或者新建线程去进行数据处理的时候,处理完,想要更新 UI 的时候,需要调用一下 Dispatcher.Invoke,将处理完的数据推入到 ...
- 反射、静态代理、动态代理(jdk、cglib)
一.反射 反射在之前的文章中详细的解释过了,简单概括就是:可以动态的获取到一个类内部的所有的信息,动态的去创建对象和使用对象以及可以操作对象的属性和方法. 二.代理 首先解释一下代理:使用一个代理对象 ...
- C++ 部分函数
string库 1.size()与length() 字符串长,结果相同 string s; s.length(); //s.length()-1是最后一个字符的下标,而不是'\0' for(i=0;i ...
- webstorm安装vue插件及安装过程出现的问题
想要编辑器识别vue文件需要安装vue插件 1. 安装方法: File--> setting --> plugin ,点击plugin,在内容部分的左侧输入框输入vue,会出现1个关于 ...
- vue初步构建项目
新建项目文件夹 在当前文件夹打开命令行工具(shift+右键-->在次此处打开命令窗口) npm install -g vue-cli npm init webpack npm install ...
- 递归——深度优先搜索(DFS)——以滑雪问题为例(自顶而下)
一.问题:滑雪 问题描述:小明喜欢滑雪,为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你.小明想知道在一个区域中最长底滑坡.区域由一个二维数组给出.数组的每 ...
- Goland 时间转换的那些事
Goland 时间转换的那些事 在项目的开发过程中遇到的一个很有意思的时间转换问题 例子 假设有一个需求,是从数据库获取到了一个时间,然后需要把时间延后一天,再返回时间戳 得到伪代码 t := &qu ...
- 『现学现忘』Docker常用命令 — 20、容器常用命令(二)
提示:接上一篇 目录 9.后台启动容器 10.查看容器日志 11.查看容器内运行的进程 12.查看容器内部细节 9.后台启动容器 后台启动容器也叫启动守护式容器. 命令:docker run -d 镜 ...
- 基于Zookeeper的分布式锁(干干干货)
原文地址: https://juejin.im/post/5df883d96fb9a0163514d97f 介绍 为什么使用锁 锁的出现是为了解决资源争用问题,在单进程环境下的资源争夺可以使用 JDK ...
- k8s原来这么简单(二)安装k8s1.23集群
官方文档:安装 kubeadm 安装条件 多台Linux机器 CentOS7 2G以上RAM,2个以上CPU 集群网络互通,可访问外网 关闭防火墙,关闭swap分区 准备安装环境 node IP k8 ...