数据在内存中的存储

数据的基本类型


/*
    1.数据的基本类型
        char        1
        short        2
        int            4
        long        4/8
        long long    8
        float        4
        double        8
        规定:
            sizeof(long) >= sizeof(int)
            32位        long    4
            64位        long    8
*/

整型家族


/*
    整数定义范围的头文件为 limits.h

    整型家族
    char  //char到底是unsigned char还是signed char 这在C语言标准中是未定义的,取决于编译器的实现
    unsigned char
    signed char

    short == signed short
    unsigned short
    signed short

    int == signed int
    unsigned int
    signed int

    long == signed long
    unsigned long
    signed long

    生活中有些数据是没有负数的,所以用unsigned int,比如身高,体重等
    signed int 的最高位是符号位,没有数值意义
    unsigned int的最高位具有数值意义
*/

浮点型家族


/*
    浮点型家族
    float的精度低,表示范围相对小,double精度高,表示范围相对较高
    float
    double
*/

构造类型--自定义类型 我们可以自己创建的新的类型


/*
    构造类型--自定义类型 我们可以自己创建的新的类型
        数组类型
            比如 int arr[5]的类型为 int [5]
            char sy[8]的类型为char [8]
        结构体类型
        枚举类型
        联合类型
*/

指针类型


/*
    指针类型
        char *p;
        int *p;
        void *p;
*/

空类型


/*
    空类型
    void表示空类型,无类型
    通常用于函数的参数,返回类型,指针类型
*/

整形再内存中的存储


/*
    数值有不同的表现形式
        二进制,八进制,十进制,十六进制

    整数的二进制表示有三种
        原码:最高位符号位,其余正常计算
        反码:符号位不变,其余位取反
        补码:反码+1
    整数的原码,反码,补码相同
    负数需要计算

    整数再内存中存放的是补码的二进制序列
*/

大小端介绍


/*
    0x11 22 33 44
                    低地址            高地址
    大端字节序存储        11 22 33 44    (相反)数据低位在高地址,高位在低地址
    小端字节序存储        44 33 22 11        (相同)低位在低地址,高位在高地址

*/

请简述大端字节序和小端字节序的概念,设计一个小程序来判断当前机器的字节序

//计算机读取地址的顺序是从低地址到高地址的顺序
int main()
{
    int a = 0x11223344;
    char* p = (char* )(&a);
    *p = 0;
    if (a == 0x11223300)
    {
        printf("小端存储\n");
    }
    else if (a == 0x00223344)
    {
        printf("大端存储\n");
    }
    printf("%x\n", a);
    return 0;
}

int main()
{
    union
    {
        int i;
        char a;
    }p;
    p.i = 0x00112233;
    if (p.a == 0x00)
    {
        printf("大端\n");
    }
    else
    {
        printf("小端\n");
    }
    return 0;
}

signed char与unsigned char在内存中存储的二进制范围

/*
        signed char在内存中存储的二进制范围
        00000000    0
        00000001    1
        00000010    2
        ......        ......
        01111110    126
        01111111    127
        10000000    **内存直接定义为  -128
        10000001    -127
        10000010    -126
        ........    ......
        11111110    -2
        11111111    -1


        unsigned char在内存中存储的二进制范围  没有符号位,最高位具有数值意义
        00000000    0
        00000001    1
        00000010    2
        ......        ......
        01111110    126
        01111111    127
        10000000    128
        10000001    129
        10000010    130
        ........    ......
        11111110    254
        11111111    255

*/

整形数据在内存中的存储,怎么打印

/*
    数据在内存中存放的数值是一回事
    怎么打印,存储方式,变量形式又是一回事
*/

int main()
{
    char a = -1;
    signed char b = -1;
    unsigned char c = -1;
    char d = -128;
    //整形提升是按照数据类型来补数据的,比如无符号型前面补0


    //在C语言中-1默认为int类型的
    //-1在内存中的补码为
    //11111111 11111111 11111111 11111111
    //但是要存储在char类型的变量中,故需要截断,将高地址的截掉
    //截掉之后为
    //11111111
    //然后在通过"="赋给变量 c
    printf("a = %d\nb = %d\nc = %d\nd = %u\n", a, b, c,d);
    //%d--打印有符号的整形
    //打印a,b同理
    //先整形提升
    // 11111111整形提升为
    // 11111111 11111111 11111111 11111111 内存中补码
    // 10000000 00000000 00000000 00000001 原码 -1

    //打印c
    //    11111111整型提升为,因为是无符号型的,所以前面补0
    //    00000000 00000000 00000000 11111111 原码255

    //打印d
    // 在内存中的补码为
    // 10000000 整形提升为
    // 11111111 11111111 11111111 10000000 在内存中的补码
    //%u--打印无符号的整形,故将上式子看成原码
    //大小为d = 4294967168

    return 0;
}

int main()
{
    char a = 128;
    // 00000000 00000000 00000000 10000000 128原码
    // 00000000 00000000 00000000 10000000 128补码
    // 10000000 存入a中的数据
    printf("%u\n", a);
    //a先整形提升到int型,因为a本身是char类型,所以最高位补符号位
    // 10000000整型提升为
    // 11111111 11111111 11111111 10000000
    // 之后无符号型打印,会将上述看成一个正数
    return 0;
}

int main()
{
    int i = -20;
    // 10000000 00000000 00000000 00010100    原码
    // 11111111 11111111 11111111 11101011    反码
    // 11111111 11111111 11111111 11101100 补码
    // 11111111 11111111 11111111 11101100 存在i中的内容
    unsigned int j = 10;
    // 00000000 00000000 00000000 00001010 10的原码和补码
    // 00000000 00000000 00000000 00001010 存在j中的内容
    printf("%d\n", i + j);
    // j是unsigned int类型,优先级大于i的int类型 故需要强制类型转换 小转大
    // 00000000 00000000 00000000 00001010 存在j中的内容
    // 11111111 11111111 11111111 11101100 存在i中的内容 此时i强制类型转换为unsigned int类型
    // 11111111 11111111 11111111 11110110  i+j后的内容
    // 通过%d的形式打印(打印有符号的整形),系统会默认上述为int类型来打印 --10
    // 10000000 00000000 00000000 00001001
    // 10000000 00000000 00000000 00001010  -10
    return 0;
}

int main()
{
    unsigned int i = 0;
    for (i = 9; i >= 0; i--)
    {
        printf("%u ", i);
    }
    //当运行到i=0时 i-- i变成-1
    // 11111111 11111111 11111111 11111111 -1在内存中的补码
    // 11111111 11111111 11111111 11111111 存放在i中的数据,类型是unsigned int类型,其值大于0
    // 故会进入死循环
    return 0;
}

#include<string.h>
int main()
{
    char a[1000];
    int i = 0;
    for (i = 0; i < 1000; i++)
    {
        a[i] = -1 - i;
    }

    /*
        a[0] = -1;
        a[2] = -2;
        ......
        a[127] = -127
        a[128] = -128    10000000
        a[129] = -129 --> 127
            10000000 00000000 00000000 10000001        -129原码
            11111111 11111111 11111111 01111110        -129反码
            11111111 11111111 11111111 01111111        -129补码
            a[129]内存储 01111111
        a[130] = -130 --> 126
            10000000 00000000 00000000 10000010        -130原码
            11111111 11111111 11111111 01111101        -130反码
            11111111 11111111 11111111 01111110        -130补码
            a[130]内存储01111110
        a[131] = -131-->125
            10000000 00000000 00000000 10000011        -131原码
            11111111 11111111 11111111 01111100        -131反码
            11111111 11111111 11111111 01111101        -131补码
            a[131]内存储01111101
        ...................
        a[255] = 1
        a[256] = 0

        共计255个

    */
    /*    
            char类型不断-1或+1思路
            char(-128----127)共256个  不算0 255个
            00000000(0)  --> 00000001(1)  .........--> 01111110(126) --> 01111111(127) 
                ↑                                                                                                     ↓
                ↑                                                                                                     ↓
            11111111(-1)<--11111110(-2)<--......<-- 10000001(-127) <--  10000000(-128)
    
            顺时针+1,逆时针-1
    */
    printf("%d\n", strlen(a));//255
    return 0;
}

unsigned char i = 0;
int main()
{
    for (i = 0; i <= 255; i++)
    {
        printf("hehe    ");
    }
    /*
        i++ --> i = i+1;
        i=0
        i=1
        .........
        i=127        
        i = 128    
        i=129
        ..........
        i=255 //11111111
        --> i = 0
        故死循环
    */
    return 0;
}

#include<string.h>
int main()
{
    // streln 的返回类型是size_t === unsigned int 类型
    if (strlen("abc") - strlen("abcdef") >= 0)
        printf(">\n");
    else
        printf("<\n");
    return 0;
}

浮点型在内存中的存储

//浮点型在内存中的存储
//浮点型定义范围的头文件为 float.h
//内存在存储的时候 解码和译码的方式要相同
// 比如以大端的形式存储到内存中,就要以大端的形式读取出来
//int main()
//{
//    int n = 9;
//    float* pFloat = (float*)&n;
//    printf(" n = %d \n", n);
//    printf(" *pFloat = %f\n", *pFloat);
//    *pFloat = 9.0;
//    printf(" n = %d \n", n);
//    printf(" *pFloat = %f\n", *pFloat);
//    return 0;
//}

浮点数存储规则


/*
    根据国际标准IEEE(电气和电子工程协会)754,任意一个二进制浮点数可以表示成下面的形式:
        V = (-1)^S * M * 2^E
        (-1)^S 表示符号位,当S为0表示整数,当S为1表示负数
        M表示有效数字 大于等于1 小于2
        2^E 表示指数位
    
    float:
    对于32位的浮点数(单精度)(写入方式均为小端)
        S:最高位 
        E:后八位
        M:最后23bit
    double
    对于64位的浮点数(双精度)
        S:最高位
        E:后11位
        M:最后52bit

    M:
    对于M的存储方式
        1 <= M <2,故M可以写成 1.xxxxxxx 的形式,其中xxxxxxx表示小数部分。
        754规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的xxxxx小数部分。
        比如保存1.01时,只保存01,等到读取的时候,再把第一位加上去。这样做的目的是节省了以为有效数字。
        以32位浮点数为例,留给M的只有23位,将第一位1舍去之后等于可以存储24位有效数字

    E
    对于E的存储方式
        1.E为一个无符号整数 unsigned int
            如果E为8位,那么他的取值范围为0-255
            如果E位11位,那么他的取值范围为0-2047.
        2.但是科学计数法中E是可以小于0的,即E可以是负数
            故754规定存入内存是,E的真实值必须再加上一个中间数
            对于8位的E,这个中间数是127;
            对于11位的E,这个中间数是1023;
            比如2^-1的E是-1,所以保存成32位浮点数时,必须保存成-1+127=126
        3.指数E从内存中取出,还可以分为三种情况
*/

int main()
{
    float f = 5.5;
    /*
        5.5
        101.1
        1.011 * 2^2
        S = 0 M = 1.011 E = 2+127=129
        S    0        0                            共一位
        M    011        01100000000000000000000        共23位
        E    129        10000001                    共8bit
        故在内存中存储形式为
        S    E            M
        0    10000001    01100000000000000000000    
        0100 0000 1011 0000 0000 0000 0000 0000
        4     0      b        0    0      0        0    0
        0x40 b0    00    00
    */
    return 0;
}
 

浮点型数据从内存中如何取出


/*
    指数E从内存中取出可以分为三种情况
    1.E不为全0也不为全1
        这时浮点数就使用以下规则表示
        E的值减去127(1023),得到真实值
        再将有效数字M前加上第一位的1.
        0.5
        0.1
        (-1)^0 * 1.0 * 2^(-1)
        E = 127 + (-1) = 126  
        01111110 E在内存中的存储形式(单精度8,双精度11) unsigned int
        尾数1.0去掉1为 0
        M = 0 
        00000000000000000000000  M在内存中的存储形式(单精度23位,双精度52位)
        则二进制表现形式为
        0 01111110 00000000000000000000000  0.5的内存表现形式(单精度32位,双精度64位)

        从内存中取出时
        将E的值减去127即为真实值 01111110(unsigned int) - 127 = -1
        在M的值前面加上1.   00000000000000000000000 ---> 1.0
        即 1.0 * 2^(-1)
    2.E全为0(+-无穷小)
        这是浮点数的指数E等于1-127(1-1023)即为真实值
        有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数。
        这样做是为了表示+-0,以及接近于0的很小的数字
    3.E全为1(正负无穷大)
        这时如果*有效数字M全为0,则表示+-无穷大(正负取决于符号位S)
*/

int main()
{
    int n = 9;
    // 00000000 00000000 00000000 00001001 9的原反补码
    // 00000000 00000000 00000000 00001001 存入n中的数据
    float* pFloat = (float*)&n;
    printf(" n = %d \n", n);
    // 00000000 00000000 00000000 00001001 n中存储的9的补码
    // 按照有符号整形打印 故打印9
    printf(" *pFloat = %f\n", *pFloat);
    // 0 000000000 0000000000000000001001 *pFloat存储的9的补码
    // S  E            M   
    // E 全0 代表无穷小
    // 故输出0.000000
    *pFloat = 9.0;
    // 9.0的二级制为
    // 1001 写成 1.001 * 2^3
    // S = 0    M = 00100000000000000000000        E = 3+127 = 130  10000010
    // 0 10000010 00100000000000000000000 *pFloat中存储的内容
    printf(" n = %d \n", n);
    // 0 10000010 00100000000000000000000 n中存储的内容
    // %d 按照有符号整形的形式打印
    // 故应该是一个很大的正数
    printf(" *pFloat = %f\n", *pFloat);
    // 0 10000010 00100000000000000000000 *pFloat中存储的内容
    // S = 0    M = 00100000000000000000000        E = 3+127 = 130  10000010
    // S = 0    M = 1.001                        E = 130 - 127 = 3
    // *pFloat = (-1)^S * M * 2^(3) = 1 * 1.001 * 2^3 = 1001 = 9.000000
    return 0;
}

  • 24
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值