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;所以隐士转换不影响值(数值比较小时)的显示,但可能会字节数不相等会影响结果精度等。