C语言printf()函数详解和安全隐患

一、问题描述

二、进一步说明

请仔细注意看,有如下奇怪的现象

   int a=5;
        floatx=a;     //这里转换是没有问题的,%f打印x是 5.000000

        printf("%d\n",a);
        printf("%f\n",a);  //输出为什么是0.000000? -----问题1
        printf("%f\n",x);
        printf("%d\n",x);  //输出为什么是0?        -----问题2
        printf("%f,%f\n",a,x);  //输出都是0.000000  为什么?            ----问题3
        printf("%f,%f\n",x,a);  //调换一下a,x的顺序,正常了,为什么?  ----问题4
        printf("%d,%f\n",a,x);

        getchar();
        return0;

三、printf()函数的原理解释

明白这些问题首先需要明白printf()函数的工作原理。

printf()维持了一个需要打印的变量栈,默认情况下,参数进栈的顺序是由右向左的,因此,参数进栈以后的内存模型如下图所示:

打印的时候,printf按照字符转换说明符规定的格式从低地址开始提取数据,直到参数打印完。

比如遇到 %f 说明符就提取8个字节的数据,遇到 %d 就提取4个字节。看到这里,你也许会问一个问题,如果后面的字节数不够了怎么办?

恭喜你,你发现了printf()的安全隐患,没错,它会强行读取临近内存的数据当作正常数据输出————很有可能产生堆溢出!

比如这样的代码:

    char string[]="Hello World!";
    printf("String: %s  ,强行再读一次: %#p , 再读一次: %#p\n", string);

输出如下:

    String:Hello World!  , 强行再读一次: 0X001C1073 , 再读一次: 0X001C1073

三、问题解释

(1) 问题1:printf("%f\n",a) 输出为什么是0.000000?

答:%f 提取8字节,a只有4字节,提取出来的数占了float表示法的指数部分,尾数部分为0,所以最终是0

(2) 问题2:printf("%d\n",x)  输出为什么是0?

答:%d 提取4字节,x有8字节,提取出来的数实际上是float表示法的指数部分(恰好是0),所以最终是0

(3) 问题3:printf("%f,%f\n",a,x); 输出都是0.000000 为什么?

答:参照问题1的解释,提取了八字节后,后面的已经乱了

(4) 问题4:printf("%f,%f\n",x,a);调换一下a,x的顺序,正常了,为什么?

答:这是正常的情况而已。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-10 23:57:17

C语言printf()函数详解和安全隐患的相关文章

C语言printf()函数详解

printf函数称为格式输出函数,其关键字最末一个字母f即为"格式"(format)之意.其功能是按用户指定的格式,把指定的数据显示到显示器屏幕上.在前面的例题中我们已多次使用过这个函数. printf函数调用的一般形式 printf函数是一个标准库函数,它的函数原型在头文件"stdio.h"中.但作为一个特例,不要求在使用 printf 函数之前必须包含stdio.h文件.printf函数调用的一般形式为: printf("格式控制字符串",

C语言sscanf()函数详解的代码

下面资料是关于C语言sscanf()函数详解的内容,希望能对各位朋友有好处. 说明:sscanf()会将参数str的字符串根据参数format来转换并格式化数据. format格式 #include <stdio.h> #include <stdlib.h> #include <string.h> int main() { int result; char str[100]; char buf1[255], buf2[255], buf3[255], buf4[255]

C语言printf()函数具体解释和安全隐患

一.问题描写叙述 二.进一步说明 请细致注意看,有例如以下奇怪的现象 int a=5; floatx=a; //这里转换是没有问题的.%f打印x是 5.000000 printf("%d\n",a); printf("%f\n",a); //输出为什么是0.000000? -----问题1 printf("%f\n",x); printf("%d\n",x); //输出为什么是0? -----问题2 printf("

C语言scanf函数详解

函数名: scanf 功 能: 运行格式化输入 用 法: int scanf(char *format[,argument,...]); scanf()函数是通用终端格式化输入函数,它从标准输入设备(键盘) 读取输入的信息.能够读入不论什么固有类型的数据并自己主动把数值变换成适当的机内格式. 其调用格式为:      scanf("<格式化字符串>",<地址表>); scanf()函数返回成功赋值的数据项数,出错时则返回EOF. 其控制串由三类字符构成: 1.格

C语言 sizeof函数详解

1. 定义:sizeof是何方神圣sizeof乃C/C++中的一个操作符(operator)是也,简单的说其作用就是返回一个对象或者类型所占的内存字节数.MSDN上的解释为:The sizeof keyword gives the amount of storage, in bytes, associated with avariable or a type (including aggregate types). This keyword returns a value of type siz

C语言main()函数详解

C的设计原则是把函数作为程序的构成模块.main()函数称之为主函数,一个C程序总是从main()函数开始执行的. 一.main()函数的形式 在最新的 C99 标准中,只有以下两种定义方式是正确的: int main( void )  /* 无参数形式 */{    ...    return 0;}int main( int argc, char *argv[] ) /* 带参数形式 */{    ...    return 0;}int指明了main()函数的返回类型,函数名后面的圆括号一

Go语言之函数详解

函数: 使用func定义函数. 1.不用前置声明 2.不支持命名嵌套定义 3.不支持同名函数重载 4.不支持默认参数 5.支持不定长变参 6.支持多返回值 7.支持命名返回值 8.支持匿名函数和闭包 函数是第一类对象,具备相同签名的看作是同一类型.第一类对象是指可在运行期间创建,可作为函数参数或者是返回值,可存入变量的实体.最常见的用法就是匿名函数. 从函数返回局部变量的指针是安全的,编译器会通过逃逸分析(escape analysis)来决定是否在堆上分配内存.函数内联是对内存分配有一定影响的

[应用相关] C 语言回调函数详解

1. 什么是回调函数? 回调函数,光听名字就比普通函数要高大上一些,那到底什么是回调函数呢?恕我读得书少,没有在那本书上看到关于回调函数的定义.我在百度上搜了一下,发现众说纷纭,有很大一部分都是使用类似这么一个场景来说明:A君去B君店里买东西,恰好缺货,A君留下号码给B君,有货时通知A君.感觉这个让人更容易想到的是异步操作,而不是回调.另外还有两句英文让我印象深刻:1) If you call me, I will call you back; 2) Don't call me, I will

【C语言天天练(二十)】scanf函数详解

引言:scanf函数虽然是学习C语言时比较早就接触的一个函数,但在使用过程中,发现真正掌握它却并不容易.本文就通过各种例子来详细的总结一下该函数的各种用法,假设它的调用格式为 scanf("<格式化字符串>",<地址表>). 1.一般使用scanf函数时都是为某个变量赋值,不考虑它的返回值.但是任何函数都是需要返回的(即使返回类型用void,也可以认为只是调用了return语句,只是并没有返回什么东西而已),同样的scanf函数也是有返回的,它的返回值是成功读取