C语言之数据的储存

目录

数据类型的介绍

类型的意义:

类型的基本归类

整形家族

字符型插曲

浮点数家族(实型)

C语言中表示小数的两种方式

构造类型(自定义类型)

指针类型

空类型(无具体类型)

整形在内存中的存储

原码反码与补码

补码思想

大端小端字节序

浮点型在内存中的存储

浮点数表示形式

举例说明: 

IEEE 754规定浮点数存储方式

对于有效数字M规定

对于指数E规定

从内存中取出

经典案例

数据类型的介绍

前言:在创建一个变量或者常量时,必须要指定出相应的数据类型,否则无法给变量分配内存

  • char:字符数据类型——1字节
  • short:短整型——2字节
  • int:整形——4字节
  • long:长整型——4字节
  • long long:更长得整形——8字节
  • float:单精度浮点数——4字节
  • double:双精度浮点数——8字节

类型的意义:

  • 使用这个类型开辟内存空间的大小(大小决定了使用范围)
  • 如何看待内存空间的视角 

类型的基本归类

整形家族

char(字符型)

  • 无符号字符型:unsigned char
  • 有符号字符型:signed char

short(短整型) 

  • 无符号短整型:unsigned short
  • 有符号短整型:signed short

int(整型) 

  • 无符号整型:unsigned short
  • 有符号整型:signed short

long(长整型) 

  • 无符号长整型:unsigned long
  • 有符号长整型:signed long

字符型插曲

作用:字符型变量用于显示单个字符

语法:char ch= 'a';

注意:

  • 在显示字符型变量时,用单引号将字符括起来,不要用双引号
  • 单引号内只能有一个字符,不能是字符串
  • C和C++中字符型变量只占有一个字节
  • 字符型变量并不是把字符本身放到内存中储存,而是将对应的ASCII码放入到储存单元

案例演示

#include <iostream>
using namespace std;
int main() 
{
	int a = 98;
	int a1 = 'b';
	char b = 98;
	char b1 = 'b';
	cout << "a的值为:" << a << endl;//98
	cout << "a1的值为:" << a1 << endl;//98
	cout << "b的值为:" << b << endl;//b
	cout << "b1的值为:" << b1 << endl;//b
	system("pause");
	return 0;
}

注意:本质上字符的储存就是将字符对应的ASCII码存到内存中,若以int类型接收得到的就是int类型数据,若以char类型接收,得到的就是char类型数据

浮点数家族(实型)

单精度浮点型:float

双精度浮点型:double 

C语言中表示小数的两种方式

  • 直接用小数点表示:3.14
  • 科学计数法表示:314e-2 

构造类型(自定义类型)

数组类型

结构体类型 struct

枚举类型 enum

联合类型 union

指针类型

int* pi;

char* pc;

float* pf;

void* pv;

空类型(无具体类型)

void

函数返回类型:void test();

函数参数:void test(void);

无具体类型的指针:void* p;

注意:对于无具体类型的属性,任意类型的数据都可放入p但是不能用,使用时需对p进行强制转换为确定类型 

#include <stdio.h>
void print(void) {
	printf("hello");
}
void main() {
	print();
}

整形在内存中的存储

数据在内存中以二进制的形式储存

原码反码与补码

对于整数来说,整数的二进制有3种表示形式:原码,反码,补码。

正整数:其原码,反码,补码相同

负整数:其原码,反码,补码要进行计算

机器数:一个数在计算机中的二进制表示形式,机器数带符号,正数在最高位放0,负数放1

真值:带符号位的机器数对应的真正数值

原码:符号位加上真值的绝对值

反码:正数反码为其本身,负数反码在原码的基础上符号位不变,逐位取反。

补码:正数补码为其本身,负数补码=反码+1.

eg:-10

  • 原码:10000000000000000000000000001010
  • 反码:11111111111111111111111111110101
  • 补码:11111111111111111111111111110110

注意:整数在内存中储存的是其二进制的补码

原因:使用补码可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理(cpu只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。

补码的创建是针对负数的计算,正整数的原码,反码,补码都相同

补码思想

在这里插入图片描述

 现在是9点,如果我想调到6点;

9 - 3 -> 6 往前拨3个小时——(-3为源码)
9 + 9 -> 6 往后拨9个小时——(9为补码)

这里称12为模,写作mod12; 称9是-3以12位模的补数,记作 -3≡+9(mod 12)

由于前面9和-3互为补数且是以12为模,此刻我们先抛开负数不提得到9+3=12(反正最后在给任意一个变量加上符号,这两个数便互为补码)

一个 N 位的二进制数,可表示的最大值是2^N-1;
假设存在 x+y = 2^N-1 --> x+y+1 = 2^N;
如果此时把2^N 当做模 --> -x(如今加上负号) 和 y+1 就互为补数;
而x+y = 2^N-1,2^N-1是一个 N 位的二进制数最大的数了(就是各位是1的数),如果x和y相加真要得到这个数那么就两个从各位逐个相加一位是1那么第二个数的该位必定是0,现在我们已经知道了x和y逐个位相反,然而-x与y+1为补码啊,那么由反码定义可知-x与y必为反码。

C语言中加上一个数就等于加上这个数的补数(本质:运算溢出情况)。

运算溢出(以char为例)

char类型一字节范围:-128——127;

注意:无符号char类型一字节范围:0——255;

运算相加减遵循顺序(本质:整形提升截取)

……-128——0——127——- -128——0——127……


大端小端字节序

触发条件:数据的大小高于1字节(地址管理的内存大小)

内存有低地址和高地址之分

高字节序与低字节序

eg:1234——字节序从左到右逐渐降低

大端字节序:把数据低位字节序的内容存放在高地址出,把数据高字节序内容存放在低地址处

小端字节序:把数据高位字节序的内容存放在高地址出,把数据低字节序内容存放在低地址处

例子:00000001

 不管是大端还是小端字节序,最后都能将其还原成00000001(只不过是存放方式的问题)


浮点型在内存中的存储

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

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

浮点数的两种写法

  • 一般写法:3.14159
  • 科学计数法:1E10(1.0*10^10)

注意:浮点型指针解引用是向内存中拿一个浮点类型的数

#include <stdio.h>
void main() {
	int n = 9;
	float* pf =(float*) &n;
	printf("n=%d\n", n);//9
	printf("pf=%f\n", *pf);//浮点数视角取0.000000
	*pf = 9.0;
	printf("n=%d\n", n);//整数视角取1091567516
	printf("pf=%f\n", *pf);//浮点数视角取9.000000
}

由此观之:浮点数和整数在内存中的存储方式一定有区别

浮点数表示形式

根据IEEE(电器和电子工程协会)754,任意一个二进制浮点数V可以表示成下面的形式

举例说明: 

浮点数:5.5——10进制

转化为二进制

5:101

0.5:2^-1

得到:101.1——>分别对应2^2,2^1,2^0,2^-1

推出:1.011*2^2——>(-1)*0*1.011*2^2

其中:S=0,M=1.011,E=2

由此观之,只要有S、M、E储存好,那么这个浮点数也就储存好了

IEEE 754规定浮点数存储方式

对于float(32位)浮点数,最高的一位是符号位S,接着的8位是指数E,剩下的23位是有效数字M

对于double(64位)浮点数,最高的一位是符号位S,接着11位是指数E,剩下的52位是有效数字M

对于有效数字M规定

对于有效数字M,因为0=<M<2,因此M可以写成1.xxxxx,因为1是确定的,在IEEE 754规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保留后面的小数部分,等到读取的时候再把这个1加上,并且,小数点后位如果没填满23/52位,则之后用0填补。

这样做的目的是:节省一位有效数字,以32位浮点数为例,留给M的只有23位,将第一位的1舍弃以后,等于可以保存24位有效数字

对于指数E规定

如果E的数字没有填满8/11位则前面补0(反正没符号)

因此,对于(-1)*0*1.011*2^2——S=0,M=1.011,E=2

在计算机存储为:[0](0) [100 0000 1](2+127) [011 0000 0000 0000 0000 0000](011)

0100 0000 1011 0000 0000 0000 0000 0000——5.5

从内存中取出

E不全为0或E不全为1

指数E的真实值减去127/1023,得到真实值,再将有效数字M前加上第一位的1

E全为0

1.xxxxx*2^-127——0.1xxxxx*2^-126——0.xxxxx*2^-126 

E全为1

这时,如果有效数字M全为0,表示+/-无穷大(正负取决于符号位S)

经典案例

#include <stdio.h>
void main() {
	int n = 9;
	float* pf =(float*) &n;
	printf("n=%d\n", n);//9
	printf("pf=%f\n", *pf);//浮点数视角取0.000000
	*pf = 9.0;
	printf("n=%d\n", n);//整数视角取1091567516
	printf("pf=%f\n", *pf);//浮点数视角取9.000000
}

理解:

n=9:00000000000000000000000000001001

以整形打印就是9(原码、反码、补码均一样)

以浮点数形式拿出

[0](S) [00000000](E) [00000000000000000001001](M)

E全为0——0.00000000000000000001001*2^(1-127)约等于0

*pf=9.0: 1001.0——1.001*2^3——(-1)*0*1.001*2^3

[0](S) [10000010](130——E) [00100000000000000000000](M) 

01000001000100000000000000000000

以整数形式拿出(其为补码,拿出原码——就是本身)

以浮点数形式拿出——9.0

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值