C语言-数据的存储

C语言–数据的存储

内置数据类型

  1. char 字符数据类型
  2. short 短整型
  3. int 整形
  4. long 长整形
  5. long long 长长整形
  6. float 浮点型
  7. double 双精度浮点型

整形家族

  1. char
    1. signed char 有符号的char
    2. unsigned char 无符号的char
  2. short
    1. signed short 有符号短整型
    2. unsigned short 无符号短整型
  3. int
    1. signed int
    2. unsigned int
  4. long
    1. signed long
    2. unsigned long
  5. long long
    1. signed long long
    2. unsigned long long

浮点型家族

  1. float
  2. double
  3. long double 不是所有编译器都支持

构造类型(自定义类型)

  • 数组 int arr[10] = {0};
  • 结构体 struct
  • 枚举 enum
  • 联合体 union

指针类型

  • char *
  • int *
  • float *
  • void *

空类型

void 表示没有类型, 无具体指定类型, 通常应用到函数的返回类型, 或者函数的参数.

int 在内存中的存储

int 类型在内存中非配4个字节

int main() {
    //用vs 在内存中查看a的的存储是 14 00 00 00
    //倒着读是00 00 00 14, 是十六进制, 是20;
    int a = 20;

    //b在内存中的存储是 f6 ff ff ff
    //倒着读是 ff ff ff f6
    //4个字节 32 bit
    //10000000000000000000000000001010 这是-10的源码,直接改符号位为1
    //11111111111111111111111111110101 反码, 符号位不变,其他位取反
    //11111111111111111111111111110110 补码, 给反码+1
    //转换成十六进制为 ff ff ff f6
    int b = -10;
    return 0;
}

了解整数在内存中是如何存储的需要了解三个东西

  • 源码
  • 反码
  • 补码

计算机中有符号数的三种表现形式即原码,反码,补码.
三种表示方法均有符号位和数值位两部分, 符号位用0表示正,用1表示负.
三种表示方法各不相同.

回到上段代码中. 整数在内存中存储的是整形的补码, 正数的三码是相同的, 而负数的三码是需要计算的.

为什么需要存储补码呢?

在计算机系统中, 数值一律用补码来表示和存储, 原因在于, 用补码可以讲符号位和数值域统一处理. 同时,加减法也可以统一处理(CPU没有加法器). 此外, 补码与原码相互转换, 其运算过程是相同的, 不需要额外的硬件电路.

1 - 1 = 0
1 + (-1) = 0
如果用原码计算
00000000000000000000000000000001
10000000000000000000000000000001
相加之后是-2

如果用补码计算
00000000000000000000000000000001
//计算补码
10000000000000000000000000000001
11111111111111111111111111111110
11111111111111111111111111111111
发现-1的补码全是1, 这样-1的补码和1的补码相加 超出了32bit, 所以32bit全部变成了0.

整数在内存中的存储方法(为什么要倒着读)

0x 11 22 33 44

一个内存地址

低地址                     高地址

11 22 33 44                44 33 22 11

正着                    倒着

大端字节序存储               小端

大端字节序存储

把一个数据的低位字节的内容, 存放在高地址处

把一个数据的高位字节内容, 存放在低地址处

小端字节序存储

把一个数据的低位字节内容, 存放在低地址处

把一个数据的高位字节内容, 存放在高地址处

从上面代码, 在vs中内存可以看出, 电脑用的是小端存储.

笔试题

简述大端小端字节序存储的概念, 并设计一个小程序来判断当前系统的字节序.


int OrderCheck() {

    int a = 1;
    char * ptr = (char *) &a;
    return * ptr;
    //也可以直接 return *(char*) &a;
}

int main() {
    
    if (OrderCheck() == 1) {
        printf("大端");
    } else {
        printf("小端");
    }
    return 0;
}

程序输出内容是什么

int main() {

    char a = -1;
    signed char b = -1;
    unsigned char c = -1;
    //首先看-1的补码是
    //11111111111111111111111111111111
    //然后char类型只有1byte, 8bit 所以会发生截断
    //截断了低八个bit位, 也就是从右数八个1111 1111
    //所以a在内存中, 是ff, 但是最后用%d, 也就是整形打印
    //所以会发生有符号位的整形提升, 也就是补码全部补1, 32个1
    //从补码求源码, 就是-1. 所以输出-1, sign char和char是等价的
    //所以b的输出和a一样, unsigned char c也是8bit
    //但是最后整形提升时是无符号的, 所以全部补0,补码的符号位是0, 所以被判定位正数直接输出了, 也就是255
    printf("a = %d, b = %d, c = %d\n", a, b, c);

    return 0;
}
int main() {
    char a = -128;
    //补码
    //1111 1111 1111 1111 1111 1111 1000 0000
    //截断 1000 0000 --a
    //%u 表示无符号正数
    //先整形提升, 补码和截断前相同
    //无符号数没有符号位, 直接就按照补码输出, 就是刚开始补码对应的值, 知识把首和bit算成数值而不是符号.
    printf("%u\n", a);
}
int main() {

    int i = -20;
    unsigned int j = 10;
    //1111 1111 1111 1111 1111 1111 1110 1100
    //0000 0000 0000 0000 0000 0000 0000 1010
    //相加
    //1111 1111 1111 1111 1111 1111 1111 0110
    //得到补码, -1得到反码
    //1111 1111 1111 1111 1111 1111 1111 0101
    //取反得到原码
    //1000 0000 0000 0000 0000 0000 0000 1010;
    //答案是 -10;
    printf("%d\n", i + j);
}

int main() {
    char a[1000];
    for (int i = 0; i < 1000; i++) {
        a[i] = -1 - i;
    }
    printf("%d\n", strlen(a));
    return 0;
}
int main() {
    unsigned char i = 0;
    //因为unsigned char类型范围是 0 - 255
    //所以会无限循环
    for (i = 0; i <= 255; i++) {
        printf(1);
    }
}

浮点型在内存中的存储

int main() {

    int n = 9;
    float *pFloat = (float *) &n;
    printf("n 的值位: %d\n", n);
    printf("*pFloat 的值位: %d\n", *pFloat);

    *pFloat = 9.0;
    printf("n 的值位: %d\n", n);
    printf("*pFloat 的值位: %d\n", *pFloat);

    
}

保存浮点数的方法是依据IEEE745标准, S,M,E的格式, 其中1<= M <= 2, M全部用来存储小数点后面的位. E中存放的是无符号数.

单精度浮点数存储 S(1bit) E(8bit) M(23bit)

双精度浮点数存储 S(1bit) E(11bit) M(52bit)

int main() {
    float f = 5.5;
    //101.1
    //1.011 * 2 ^ 2
    //(-1) ^ 0 * 2 * 1.001 * 2 ^ 2
    //S = 0
    //M = 1.011
    //E = 2
    //2 + 127 = 129;
    //5.5存入内存如下
    //0100 0000 1011 0000 0000 0000 0000 0000
    //40 B0 00 00 小端存储在内存中显示为 00 00 B0 40
    return 0;
}

对有些浮点数不能精确的保存

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值