#9数据的存储#

1.数据类型介绍

char        //字符数据类型

short       //短整形

int            //整形

long          //长整形

long long   //更长的整形

float          //单精度浮点数

double      //双精度浮点数

整形:

char
    unsigned char
    signed char
short
    unsigned short [int]
    signed short [int]
int
    unsigned int
    signed int
long
    unsigned long [int]
    signed long [int]

浮点数:

float
double

构造类型:

数组类型
结构体类型 struct
枚举类型 enum
联合类型 union

指针类型:

int *pi;
char *pc;
float* pf;
void* pv;

空类型:

void 表示空类型(无类型)

通常应用于函数的返回类型、函数的参数、指针类型。

2.整形的存储

(1)原码 反码 补码

有符号位和数值位

符号位是最高位

符号位是0 表示是正数

符号位是1 表示是负数

十进制转化成二进制时得到的是原码

但在计算机中存储计算时用的是补码

正数

原码 反码 补码相同

负数

反码是原码符号位不变 数值位按位取反得到的

按位取反就是0变1 1变0

补码等于反码加1

 

存储的是补码

但是顺序会出现问题

这是为什么呢?

这涉及到大小端问题

(2)大端和小端

大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址 中;

小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位,保存在内存的高地址中。

相对位置

高位                        低位

低地址                     高地址

大端:也就是正着存进去

小端:也就是倒着存进去

练习

写一段代码告诉我们当前机器的字节序是什么

#include<stdio.h>
check_sys()
{
    int a=1;
    char *p=(char*)&a;//存放地址 解引用只拿一个字节
    return *p; 
    //返回1 小端
    //返回0 大端

    //指针类型的意义
    //1 指针类型决定了指针解引用操作符能访问几个字节
    //2 指针类型决定了指针+1 -1 到底加的 减的是几个字节 
}

int main()
{
    int ret=check_sys();
    if(ret==1)
    {
        printf("小端\n");
    }
    else
    {
        printf("大端\n");
    }
    return 0;
} 

    //可以再优化函数内部

    int a=1;
    return *(char*)&a;

大端模式

0x11223344 11 22 33 44正着存

小端模式

0x11223344 44 33 22 11倒着存

拿1来进行判断

0x00000001 

大端 00 00 00 01

小端 01 00 00 00

判断第一个字节不同就可以了

char*进行强制类型转换

char范围:

有符号char范围-128到127 补码反推原码 
无符号char范围0到255      补码就是原码

 

上面是无符号数的范围

需要说明的是符号位不会借位

也就是说补码10000000对应的就是-128

-128

原码1 10000000

反码1 01111111

补码1 10000000

因为char是1个字节 只有8个bit位

所以-128的补码就为10000000

补码的相加规律

127+1=-128

再加1就是-127 一直到-1 再加1就是0 完美闭环

练习

1输出什么?

#include <stdio.h>
int main()
{
    char a= -1;
    signed char b=-1;
    unsigned char c=-1;
    //c:11111111 无符号位补0 
    //补码:0000000000000011111111
	//正数 原反补相同 
	//打印原码 255 
    printf("a=%d,b=%d,c=%d",a,b,c);
    return 0;
}

a=-1 b=-1 c=255

a:

-1原码:10000000 00000000 00000000 00000001
-1反码:11111111 11111111 11111111 11111110
-1的补码是全1
char 1个字节 8个bit位 截断 
a:11111111
整型提升
补符号位 1 
补码:11111111111111111111111111111111111
存的是补码 打印原码 还是-1 

b:

b:11111111
同a

c: 

c:11111111 无符号位补0 
补码:0000000000000011111111
正数 原反补相同 
打印原码 255 

注意整型提升

2

#include <stdio.h>
int main()
{
    char a = -128; 
    printf("%u\n",a);
    return 0;
}

-128原码:1000000000010000000
-128反码:0111111111101111111
-128补码:0111111111110000000
char截断:10000000
%u打印10进制无符号位
char整型提升 补符号位 补1 
整型提升后,还是补码:111111111111111111111110000000 前面25位是1 后7位是0
因为打印无符号数
原码就是补码

所以打印一个很大的数

3

#include <stdio.h>
int main()
{
    char a = 128;
    printf("%u\n",a);
    return 0;
}

原00000001000000
补00000001000000
10000000截断 
0000000001000000提升 补 
0000000001000000原
128存不下
看成127+1 补码加1 最后是-128
所以和第2题结果一样 

4

int i= -20;
unsigned  int  j = 10;
printf("%d\n", i+j);

输出-10

根据补码相加规律可得

不放心可以计算

-20

原10000000 00000000 00000000 00010100

反111111111 111111111 111111111 11101011

补111111111 111111111 111111111 11101100

10

原00000000 00000000 00000000 00001010

补00000000 00000000 00000000 00001010

补码相加

补11111111 11111111 11111111 11110110

反11111111 11111111 11111111 11110101

原10000000 00000000 00000000 00001010

原码为最后结果-10

5

unsigned int i;
for(i = 9; i >= 0; i--)
{
    printf("%u\n",i);
}

无符号数 永远是正数

所以陷入死循环

先输出9 8 7 6 5 4 3 2 1 0

负数开始 符号位会被当成有效位 所以原码很大

所以是一个很大的数 一直循环

6

#include<stdio.h> 
int main()
{
    char a[1000];
    int i;
    for(i=0; i<1000; i++)
    {
        a[i] = -1-i;//-1到-1000
    }
    printf("%d",strlen(a));
    return 0;
}

255

char有符号范围-128-127

所以到-129时会看成-128-1

得到127

依次类推最后可以得到0

前面128个负数加上127到1的127个数

共255个数

0是第256个数 0不算strlen中的长度

所以最后输出255

7

#include <stdio.h>
unsigned char i = 0;
int main()
{
    for(i = 0;i<=255;i++)
    {
        printf("hello world\n");
    }
    return 0;
}

char无符号数范围0-255

所以陷入死循环

256看成255+1

255+1=0(补码相加)回到0

总结:

1先写出数的原码反码补码 注意正数原反补相同 负数要根据规则来计算 最后是补码的计算

2小心char只占1个字节 补码需要截断

3char截断补码后 整型提升 补充符号位 负数补1 正数补0

4补完之后进行补码的相加减

5相加减完后返回成原码 小心正数负数计算方式不同

6最后输出结果为原码

有的题有的步骤没有

注意char无符号数和有符号的范围 小心题目出现死循环

小心题目中带有无符号数和有符号数的条件 整型提升不要补错数字了

补码的计算规则需要知道 

char无符号 127+1=-128

char有符号 255+1=0

加减后可以知道补码对应原码后输出的数

归根结底是补码的计算 中间有很多细节步骤要到位 还有最后的还原

3.浮点型在内存中的存储

(1)浮点数

3.14159

1E10

浮点数家族包括: float、double、long double 类型。

浮点数表示的范围:float.h中定义

(2)存储规则

与整型存储规则不同

任何一个二进制浮点数可以写成以下形式

(-1)^S * M * 2^E

(-1)^s表示符号位,当s=0,V为正数;当s=1,V为负数。

M表示有效数字,大于等于1,小于2。

2^E表示指数位(E的大小类似于科学计数法10的指数)

比如说

0.5
二进制形式0.1
(-1)^0*1*2^(-1)
S=0 M=1.0 E=-1

5.5
二进制形式101.1
(-1)^0*1.011*2^2
S=-1 M=1.011 E=2

(3)存储方式

5.5写成标准形式的数据已经得到(float型)(32位)

第一位是符号位

后面八位是E+127后的二进制形式

后面的位再是M小数点后的数字 正常写

没有到32位的位数全部用0补齐

所以

0 10000001(129) 011(1.011) 00000000000000000000

01000000101100000000000000000000

写成16进制

0100 0000 1011 0000 0000 0000 0000 0000

二进制四位对应一个十六进制位

0x4 0 b 0 0 0 0

结果为0x40b0000

如果是double型(共64位)

第一位是符号位不变

后面23位变成E+1023的二进制形式

后面的位再是M小数点后的数字 正常写

没有到64位的位数全部用0补齐

特殊情况(反过来推)

如果E全为0(整个数就是无穷小)

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

如果E全为1(整个数就是无穷大)

E全为1 这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s);

看这段代码

int main()
{
	int n = 9;
	float *pFloat = (float *)&n; 
	printf("n的值为:%d\n",n);
	printf("*pFloat的值为:%f\n",*pFloat);
	*pFloat = 9.0;
	printf("num的值为:%d\n",n);
	printf("*pFloat的值为:%f\n",*pFloat);
	return 0;
}

9:

0 00000000 0000000000000000001001-补码

E全为0 整个数就是无穷小

(-1)^0*0.0000000000000000000001001*2^-126-标准形式 这是补码 因为正数 也是原码

第一个结果输出9的原码就是9

第二个结果就为0.00000000(float保留)

9.0:

1001.0-二进制
1.001*2^3
(-1)^0*1.001*2^3
S=0 M=1.001 E=3
0 10000010 00100000000000000-标准形式 这是补码 因为正数 也是原码

第三个结果输出一个很大的数

第四个结果是9.0

总结:

1十进制数转化成二进制数
2写成标准形式 得到S M E
3先确定符号位 符号位后面存E float加个127存 double加个1023存 存的时候写成二进制
4再放M小数位
5最后补0
6分成4个一组 变为十六进制

#9数据的存储#完

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力的小恒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值