C语言数据的存储

内存分布

        内存中有很多的分区,讲一下栈区、堆区和静态区。

        栈区是存储局部变量、函数形参以及为函数调用开辟空间的区域,栈区会优先使用高地址的空间,再使用低地址的空间。栈区的空间是由编译器自动维护的。栈区上的变量不初始化默认是随机值。

        堆区是动态开辟的空间,堆区由程序员自己申请使用,需要自主释放申请的空间,否则会造成内存泄漏。如果程序员没有释放,程序结束的时候操作系统自动回收该空间。并不是所以程序都会结束,网上的一些服务,只有在维护的时候才需求结束,其它时间需要程序一直运行着,内存泄漏是一个很严重的问题,一直申请而不释放,后面会导致程序崩溃。

        静态区是存储全局变量以及static修饰的变量,这些值不初始化默认是0。

        下面这个代码十分依赖环境,环境不一样可能结果也不一样,在vs2019编译器的debugx86环境下运行的。

#include <stdio.h>

int main()
{
    int i = 0;
    int arr[5] = { 1,2,3,4,5 };
    printf("i的地址%p\n", &i);
    printf("arr[7]的地址%p\n", &arr[7]);
    for (i = 0; i <= 7; ++i)
    {
        arr[i] = 0;
        printf("%d\n", i);
    }
    return 0;
}

        这个程序会死循环,先在高地址创建变量i,再在低地址创建数组arr,数组随着下标的增长地址是由低到高变化的。i和数组最后一个元素的地址相差两个整型,八个字节,即arr[5]和arr[6],当数组访问到arr[7]的时候,arr[7]的地址是和i的地址是一样的,修改arr[7]的值,也会修改i,i变为0,继续执行for循环,程序死循环。

整型的存储

        计算机内存中存储整数是以整数的补码存储的。

正整数:

        原码:直接将整数转换成二进制,符号位(最左边)是0。

        正整数的原码、反码和补码是一样的。

负整数

        原码:直接将整数转换成二进制,符号位是1。

        反码:原码除了符号位全部二进制位取反(0变1,1变0)。

        补码:反码+1得到补码。

        补码变原码,先-1得到反码,然后除了符号位全部取反得到原码。

正整数

        11 = 2^0(右往左第一位) 2^1(右往左第二位)+ 2^3(右往左第四位)符号位是0。

        原码:00000000        00000000        00000000        00001011(隔开方便看)

        反码:00000000        00000000        00000000        00001011

        补码:00000000        00000000        00000000        00001011

负整数

        -11 = 2^0(右往左第一位) 2^1(右往左第二位)+ 2^3(右往左第四位)符号位是1。

        原码:10000000        00000000        00000000        00001011

        反码:111111111        111111111        111111111        11110100        符号位不变,原码取反

        补码:111111111        111111111        111111111        11110101        补码+1

大小端 

        大端字节序存储:数据的低位保存在内存的高地址中,数据的高位保存在内存的低地址中。

        小端字节序存储:数据的低位保存在内存的低地址中,数据的高位保存在内存的高地址中。

判断大小端方法

#include <stdio.h>

int main()
{
    int a = 1;
    char* pa = (char*)&a;
    if (*pa == 1)
        printf("小端\n");
    else
        printf("大端\n");
    return 0;
}

浮点数的存储形式

        float和int都是四个字节的大小,但是存储的数据并不一样。

        将int类型的地址存储在flota类型的指针,解引用float类型的指针,拿到的值跟int类型的数据不一样,说明float和int两个类型存储数据的方式是有所差异的。

        浮点数都可以表示成 (-1)S*M*2^E 。

        S表示符号位,浮点数为正数,S是0;浮点数为负数,S是-1。

        M是科学计算法的二进制数,小数点前面一定是1。

        E是浮点数的二进制表示形式移动成M的位数,数据往右移是正数,数据往左移是负数。

        单精度浮点数的存储形式

        最高的1位是符号位s,接着的8位是指数E,剩下的23位为有效数字M。

        双精度浮点数的存储形式

        最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M。

        M是科学计算法的二进制形式,第一位一定是1,因此可以舍去第一位,只保存后面的小数部分,使用的时候再将第一位的1补上。多一位存储数据,存储的数据精度更高了。

        规定E为一个无符号整数。单精度浮点数的时候,E有8个bit位,取值的范围是0~255。双精度浮点数的时候,E有11个bit位,取值的范围是0~2047。但是科学计算法中的E可以是负数,所以必须要加一个修正值再存储。单精度浮点数,E需要加上127;双精度浮点数,E需要加上1023。取出数据的时候再减这个修正值。

        当E加上修正值的时候为全0,浮点数的指数E等于1-127(或者1-1023)。有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数。这样做是为了表示±0,以及接近于 0的很小的数字。

        当E加上修正值的时候为全1,表示这个浮点数为±无穷大。

        注:有一些浮点数无法精确存储,会有四舍五入的情况。

        3.75的二进制表示形式为11.11,2^1 + 2^0 + 2^(-1) + 2(-2)。

        (-1)^0 * 1.111 * 2^1。3.75是正数,S是0;二进制数是11.11,移动二进制数变成科学计算法的数据M是1.111;二进制数移动变成科学计算法的数据向右移动了一位,E是1。如果是单精度浮点数,E加上修正值127变为128。当M不够23位的时候,后面补0。

        S是0。E是1000 0000。M是111 0000 0000 0000 0000 0000

        内存中存储:0100 0000 0111 0000 0000 0000 0000 0000 (十六进制:0x40700000)

        小端字节序存储,提取数据0x40700000。

浮点数比较

        浮点数不能直接比较大小,因为有一些数是不能精确保存的。

        需要使用一个精度范围进行判断。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值