【C语言】数据在内存中的存储

文章目录

数据在内存中的存储

整数

前提知识

(1)原反补码

  • 内存中都是补码
  • 正数原反补码相同
  • 负数都不同
    • 第一位二进制是符号位,1
    • 后面是正常的二进制
    • 原码符号位不变,其他位取反得反码,再加一得补码
    • 补码符号位不变,其他位取反再加一也可得原码

(2)大小端

  • 为什么会有大小端

    • 计算机的单位是字节,一个字节是8个bit(0/1),
    • 一个int是4字节,是32个0/1,是8个16进制数字
    • 接下来就有如图的两种可能
  • vs中是那种可能性呢?答案是可能性2

    • 先看一眼正常情况
    • 再看一眼真实情况
      • 图中的7,8在最前面显示,而显示的是由低地址到高地址的访问,故为可能性2
  • 大小端名字的由来(来源于《格列佛游记》):

    • 首先,对于一个数字12345678,最大的数字应该是第一位的1,因为代表1000 0000
    • 其次,如图中的内存的访问,是从左向右(本质是低地址到高地址)
    • 那么,我们先看到的是最左边的(低地址),
      • 如果先看到的是最大的数字,比如12345678中的第一个1,就叫大端
      • 先看到最小的数字,就叫小端
  • 判断大小端的程序

    • 直接看int 1的第一个字节储存的内容即可
    cpp 复制代码
    #include<stdio.h>
    int main()
    {
    	int a = 1;
    	int* pa = &a;
    	if (*(char*)pa = 1)
    		printf("是小端");
    	else
    		printf("是大端");
    
    	return 0;
    }
  • 示例:

  • char i[2] 是两个字节:i[0] 对应低地址i[1] 对应高地址

    • i[0] = 0x39 → 低地址存 0x39

      i[1] = 0x38 → 高地址存 0x38

  • 字节 short k 的 低位字节 = 0x39,高位字节 = 0x38

  • printf("%x") 按十六进制打印,从高地址向低地址,输出 3839


(3)整型提升

  • 是什么:只要 char / short 参与运算、传参、printf 等操作,就会被自动转换为int

  • 为什么:CPU 的通用寄存器默认按int(32 位)宽度设计

  • 对象:short,char(包括signed和unsigned)

  • 使用场景:

    • 算术运算char + charshort - shortchar | short 等所有位运算、算术运算
    • 传参 :虽然应该传int类型,但是你也可以传char类型 ,因为char会被转化成int
      • 比如memset设置字符串,使用printf大小写转换时对char加减数字 的情况等等
      • printf如果想打印char字符的ASCII码值,使用%d,这时候char也会被转化成int
    • 作为返回值
    • if,while等条件判断
    • sizeof(char + char) 结果是sizeof(int)
  • 具体内容

    以使用printf("%u")打印两个char相加为例:

    • 在计算/打印等使用之前,先整型提升
      • 如果是unsigned char,相当于二进制直接在前面补上24个0
      • 如果是有符号char,前面补24个符号位
    • 得到的结果再转化为char类型
    • 这时候再把char转成unsigned int来打印

(4)数据的循环圈

  • 以char类型不停+1来举例(0,1,2...127,-128,-127,-126...-1,0):
    • 从0000 0000开始,一直到01111111,就是从0变成127
    • 01111111再加一就是10000000(负数的补码),这个数字默认是-128
    • 然后10000000(补码)加一得到的就是-127,继续加上数字就从-127一直加到-1,然后是0
    • 接下来就会回到第一步,是一个循环
  • 各种数据类型都有这样的过程

(5)%x用来打印16进制数字

  • 在vs中,直接得到的是有效数字,没有前面的0x和无效的0
    • 比如打印11的十六进制,直接打印b而不是0xb



6个题目


第1题

  • 设计程序判断机器是大端还是小端
  • 小端:权重小的放在低地址
  • 大端:权重大的放在低地址

第2题

  • a
    • a的原码:10000001
    • a的反码:11111110
    • a的补码:11111111
    • 打印前时整形提升为11111111 11111111 11111111 11111111
    • %d打印,看到是负数,打印对应的原码:10000000 00000000 00000000 00000001,结果是-1
  • b
    • b和a是同一种类型,打印结果相同
  • c
    • c的补码也是11111111
    • 打印前,因为是unsigned char ,整型提升为00000000 00000000 00000000 11111111
    • %d打印,看到是正数,直接打印 ,结果是255

第3题

  • a的补码:10000000(这是-128的默认补码值,没有原码和补码的概念
  • 打印前时整形提升为11111111 11111111 11111111 10000000
  • %u打印,无符号,默认是正数,直接打印,结果是4294967168
  • a的原反补码相同:10000000
  • 和上半题的补码相同,在使用%u打印前的整形提升自然也相同,结果也相同

第4题

  • 根据"数据的循环圈", char类型的+1循环:(0,1,2...127,-128,-127,-126...-1,0)

    可以得到,char类型的-1循环:0,-1,-2... -128 ,127,126...2,1,0

  • a数组元素从-1开始,到-128,再从127开始,到1,然后到了一个0,这个0是ASCII码值,strlen读到这个就会停,所以打印的结果是128+127=255


第5题

  • 由于"数据的循环圈",i的最大值就是255,再加1会变成1,会无限循环下去,不停打印
  • 同理可得,i作为unsigned,是不会出现负数的,所以也会不停打印

第6题

  • 地址如图所示,
  • 通过ptr2得到的,有因为是小端字节序,所以2是高位,
  • 使用%x打印16进制,得到的结果应该是2000000和4



浮点数

(1)浮点数的类型

  • float、32位,4字节
  • double、64位,8字节
  • long double,16字节

(2)浮点数的存储

1.存之前

  • 一个浮点数,计算机理解为为 (−1)^SM ∗ 2 ^E
    • S是0或1,决定了浮点数的正负
    • M是浮点数转为二进制后,再进行取有效数字(相当于把1234转化为1.234*10^3次方中的1.234)
      • M大于1,小于2,(和科学计数法中的转化一样)
    • E是次方数,(相当于把1234转化为1.234*10^3次方中的10的3次方中的3,不过这里是2的E次方)
  • 举例:十进制的6.0,
    • 先转化为二进制:110.0,
    • 再进行科学计数法:1.100*2的2次方
    • 那么,S=0;M=1.1;E=2

2.存的时候

  • 32位的浮点数(float):最⾼的1位存储符号位S,接着的8位存储指数E+127 ,剩下的23位存储有效数字 M的小数位
  • 对于64位的浮点数(double),最⾼的1位存储符号位S,接着的11位存储指数E+1023 ,剩下的52位存储有效数字M的小数位

(3)浮点数的读取

  • 一般情况:将二进制数字转化为对应的S,M,E ,然后再使用
  • 指数二进制部分全为0:相当于于1-127(或者1-1023),这时候还原M的时候不再加上1,直接读0.xxx,这是为了表示0或者很小的数字
  • 指数二进制部分全为1:这相当于 ± 无穷大

(4)一个题目

  • 第一个就是9

  • 第二个:将int 类型的9看做一个float进行打印,

    • 9的原反补码:00000000 00000000 00000000 00001001
    • 当做float看:
      • S(符号位)是0,代表正数
      • 接下来的8位代表指数位(E+127),全0,代表无穷小,所以打印是0(默认保留小数点后 6 位
  • 第三个:(因为float* pFloat 代表该地址存的就是一个浮点数,所以即使是*pFloat = 9 ;也依然成立)将浮点数存到原来n的位置,并且当做整型打印

    • 储存9时:1.001*2^3
    • 符号位S是0,后面 接着的8位存储指数E+127 =130(二进制是10000010),后面接着23位存1.001的小数位001
      • 就是0 10000010 00100000000000000000000
    • 作为int类型打印就是 1091567616
  • 第四个:类型符合,打印正确,默认六位小数,就是9.000000

相关推荐
旖-旎2 小时前
哈希表(字母异位次分组)(5)
数据结构·c++·算法·leetcode·哈希算法·散列表
特立独行的猫a3 小时前
OpenHarmony平台移植 gifsicle:C/C++ 三方库适配实践(Lycium / tpc_c_cplusplus)
c语言·c++·harmonyos·openharmony·三方库适配·lycium
paeamecium3 小时前
【PAT甲级真题】- All Roads Lead to Rome (30)
数据结构·c++·算法·pat考试·pat
PD我是你的真爱粉3 小时前
Redis 数据类型与底层实现:从 SDS、Quicklist 到 ZSet 跳表彻底讲透
数据结构·redis
汀、人工智能4 小时前
[特殊字符] 第100课:任务调度器
数据结构·算法·数据库架构·贪心··任务调度器
会编程的土豆4 小时前
日常做题 vlog
数据结构·c++·算法
yashuk5 小时前
C语言 vs. C++ ,哪个更适合初学者?
c语言·c++·面向对象编程·初学者·学习路径
泛凡(Linyongui)6 小时前
PY32F002B实践之四--宠物腹背理疗仪项目踩坑及项目总结复盘
c语言·keil·32位单片机·腹背理疗仪项目实践·普苒py32
旖-旎6 小时前
哈希表(存在重复元素||)(4)
数据结构·c++·算法·leetcode·哈希算法·散列表