最近使用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. scanf()函数原理

    一.三点说明 1.用户输入的字符,会以ASCII码形式存储在键盘缓冲区:2.每调用一次scanf函数,就从键盘缓冲区读走一个字符,相当于清除缓冲区:3.若用户一次输入n个字符,则前n次调用scanf函 ...

  2. C语言可变参数函数实现原理

    一.可变参数函数实现原理 C函数调用的栈结构: 可变参数函数的实现与函数调用的栈结构密切相关,正常情况下C的函数参数入栈规则为__stdcall, 它是从右到左的,即函数中的最右边的参数最先入栈. 本 ...

  3. c语言学习之基础知识点介绍(三):scanf函数

    本节继续介绍c语言的基础知识点. scanf函数:用来接收用户输入的数据. 语法:scanf("格式化控制符",地址列表); 取地址要用到取地址符:&(shift+7) 例 ...

  4. C语言之可变参实现scanf函数

    既然有printf函数可变参实现,那就一定有scanf函数的可变参实现.废话不多说,源码奉上: 本源码不过多分析,如要明白原理,请翻本博客以往的文章看说明. 欢迎关注新浪微博:http://weibo ...

  5. scanf函数的返回值

    #include <stdio.h> int main() { ]; ]); printf("%d\n", n); ; } 此刻注意scanf函数里面的格式限定,该代码 ...

  6. C语言中scanf函数的实现

    接上一篇C语言中可变参数函数实现原理,从理论上详细介绍了C语言中可变参数函数的实现,这一篇从minix内核源码中的scanf函数入手,学习C语言经典可变参数函数的实现过程 在scanf.c文件中,可以 ...

  7. 4-printf & scanf函数

    一.printf函数 这是(printf和scanf)在stdio.h中声明的一个函数,因此使用前必须加入#include <stdio.h> 1.用法 1> printf(字符串) ...

  8. 【前端】require函数实现原理

    // require函数实现原理: function require(modulePath) { var regExp = /\w+$/g; var moduleName = regExp.exec( ...

  9. C语言scanf函数详细解释

    原文链接 函数名: scanf 功 能: 执行格式化输入 用 法: int scanf(char *format[,argument,...]); scanf()函数是通用终端格式化输入函数,它从标准 ...

随机推荐

  1. 入门不容易->先从数组说起

    数据结构,平时用得最多,接触最多的也是数组,先从数组说起. 数组的概念  什么是数组 一组数据,一秒钟可以申明1000个变量的骚操作. 存储相同的类型,连续的存储空间. 最重要的一点:按下标找元素. ...

  2. C# $的简介

    无意中看到这个$格式字符串,然后学习一下.$是C#6.0的新特性. 比如我们以前是这么做的,内插字符串. var anInt = 1; var aBool = true; var aString = ...

  3. vim编辑以及脚本编程练习

    转至:http://www.178linux.com/88128 vim编辑器的使用总结: vim在工作过程当中有三种模式:编辑模式.输入模式.末行模式. 1.编辑模式:即命令模式,键盘操作常被理解为 ...

  4. PyTorch深度学习实践——反向传播

    反向传播 课程来源:PyTorch深度学习实践--河北工业大学 <PyTorch深度学习实践>完结合集_哔哩哔哩_bilibili 目录 反向传播 笔记 作业 笔记 在之前课程中介绍的线性 ...

  5. Python:pandas(三)——DataFrame

    官方文档:pandas之DataFrame 1.构造函数 用法 pandas.DataFrame( data=None, index=None, columns=None, dtype=None, ) ...

  6. Linux安装Mysql8.0及SQL分类的补充

    Linux安装Mysql8.0 参考文章:https://blog.csdn.net/qq_38570633/article/details/109257430 参考文献:https://blog.c ...

  7. 『现学现忘』Docker基础 — 14、Docker的卸载

    目录 1.查询Docker安装过的包 2.卸载Docker软件包 3.删除残留目录 4.验证是否卸载 5.20版本Docker卸载(官方文档) 1.查询Docker安装过的包 执行yum list i ...

  8. ASP.NET Core 6框架揭秘实例演示[22]:如何承载你的后台服务[补充]

    借助 .NET提供的服务承载(Hosting)系统,我们可以将一个或者多个长时间运行的后台服务寄宿或者承载我们创建的应用中.任何需要在后台长时间运行的操作都可以定义成标准化的服务并利用该系统来承载,A ...

  9. .NET 6学习笔记(2)——通过Worker Service创建Windows Service

    通过Visual Studio中的Windows Service模板,我么可以创建.NET Framework版本的Windows Service,网络上对此已有详细且丰富的各路教程.但在我们升级到. ...

  10. 高并发之 API 接口,分布式,防刷限流,如何做?

    在开发分布式高并发系统时有三把利器用来保护系统:缓存.降级.限流 缓存 缓存的目的是提升系统访问速度和增大系统处理容量 降级 降级是当服务出现问题或者影响到核心流程时,需要暂时屏蔽掉,待高峰或者问题解 ...