c语言进阶 - 数据存储 - 知识点整理

目录

一:简介库函数:

二、类型的意义:

三、unsigned char 与signed char 范围

四、构造类型:

五、 问题:为什么用补码表示比原码表示好呢?

六、大端和小端

七、浮点型在内存中的存储

八、浮点数的取出:


一:简介库函数:

库函数是独立于C语言之外的,是编译器的厂商提供给的

C语言标准也规定了一些库函数:

函数名,参数类型,返回值类型,函数功能等

size_t strlen(const char* str);
//求字符串长度
//但是每一家厂商在库函数中都可能会有一些不同
//比如vs : scanf  - scanf_s
           strcpy - strcpy_s
我们生活中无非就是整数和小数,所以划分为整型家族和浮点型家族
//整型家族:
char //字符数据类型
short //短整型
int //整型
long //长整型
long long //更长的整型

//浮点型家族
float //单精度浮点型
double //双精度浮点型

二、类型的意义:

1.使用这个类型开辟的空间大小不同

2.看待内存空间的视角不同

比如:

c语言进阶 - 数据存储 - 知识点整理_第1张图片

int 开辟4个字节的空间,float 也是开辟4个字节的空间,但是从内存空间的视角来看,

变量a里面存放的是整数,变量f里面存放的是小数 

三、unsigned char 与signed char 范围

c语言进阶 - 数据存储 - 知识点整理_第2张图片

总结:

有符号位:-(2^n-1)   -  (2^n-1)-1

无符号位:0 - (2^n)-1

四、构造类型:

1.数组类型 2.结构体类型struct  3.枚举类型 enum 4. 联合体类型 union

//数组的类型:
int main()
{
	int a = 10;
	int arr[10] = {0};
	printf("%d\n",sizeof(a));//4
	printf("%d\n", sizeof(int));//4 ,a的类型

	printf("%d\n", sizeof(arr));//40
	printf("%d\n", sizeof(int [10]));//40,所以数组arr的类型是int [10]
	return 0;
}

指针类型:

//指针类型
int* p1;
char* p2;
float* p3;
void* p4;

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


void test(void)//这里void 表明不需要参数
{
 printf("hehe\n");
}

int main()
{

    test();
}

对于整形来说:数据存放内存中其实存放的是补码

五、 问题:为什么用补码表示比原码表示好呢?

1.补码可以将符号位和数值域统一处理

2.cpu只有加法器,加法和减法可以统一处理

3.补码与原码相互转换,运算过程是相同的,不需要额外的硬件电路

c语言进阶 - 数据存储 - 知识点整理_第3张图片

解释:

c语言进阶 - 数据存储 - 知识点整理_第4张图片

 补码和原码相互转换,其运算过程是相同的,都可以通过先符号位不变,其他位按位取反,+1进行转换c语言进阶 - 数据存储 - 知识点整理_第5张图片

六、大端和小端

一个数据以字节为单位存储顺序,对于大于一个字节的数据,,那么必然存在着如何将多个字节安排的问题,所以导致了大端和小端存储模式。

c语言进阶 - 数据存储 - 知识点整理_第6张图片

 vs2019 运用的是小端存储

案例1:

c语言进阶 - 数据存储 - 知识点整理_第7张图片

 c语言进阶 - 数据存储 - 知识点整理_第8张图片

a,b 解释:   对于有符号位,先将数据写成二进制原码,通过原码转换成补码,因为a的类型是char类型,只访问8个Bit位,所以进行截断,又因为最后以%d打印,所以按符号位进行整形提升,但是因为还是在计算机内存中的,所以还是补码,因为打印需要的是原码,所以转换成原码,最后打印-1

c解释:   对于无符号位,先将数据写成二进制原码,通过原码转换成补码,因为c的类型是char类型,只访问8个Bit位,所以进行截断,又因为最后以%d打印,所以按符号位进行整形提升,因为为无符号位,所以符号位为正数,所以补0,补齐32位,因为32位都是有效位,并且为正数,所以原反补相同,所以最后打印为255

//案例2:
int main()
{
	char a = -128;
	printf("%u\n",a);
	return 0;
	//10000000 00000000 00000000 10000000 -128原码
	//11111111 11111111 11111111 01111111 补码
	//11111111 11111111 11111111 10000000反码
	//10000000 char型
	//11111111 11111111 11111111 10000000  //因为%u是以无符号数形式打印整形,所以整形提升,并且整形提升之后就为无符号数,所以原反补相同
	//4294967168
}

//案例3:
int main()
{
    int a = 128;
    printf("%u\n",a);
//00000000 00000000 00000000 10000000
//10000000 //char型
//11111111 11111111 11111111 10000000//整形提升
//4,294,967,168  
}
//案例4:
int main()
{
	int i = -20;
	unsigned int j = 10;
	printf("%d\n",i + j);
	//10000000 00000000 00000000 00010100
	//11111111 11111111 11111111 11101011
	//11111111 11111111 11111111 11101100//-20 补码
	//00000000 00000000 00000000 00001010//10的原反补
	//11111111 11111111 11111111 11110110 补码
	//10000000 00000000 00000000 00001001
	//10000000 00000000 00000000 00001010 原码
	//-10 %d 有符号位整形打印
	return 0;
}
//案例5:
int main() 
{
	char a[1000];
	int i;
	for (i = 0;i< 1000;i++)
	{
		a[i] = -1 - i;
	}
	printf("%d",strlen(a));//255
	return 0;
}

 char : -128  ---   127,strlen()直到找到'\0'停止

图解:

c语言进阶 - 数据存储 - 知识点整理_第9张图片

c语言进阶 - 数据存储 - 知识点整理_第10张图片

整形家族定义的头文件为#include

c语言进阶 - 数据存储 - 知识点整理_第11张图片

 浮点数家族定义的头文件为#include

c语言进阶 - 数据存储 - 知识点整理_第12张图片

七、浮点型在内存中的存储

根据国际标准IEEE(电气和电子工程协会)754,任意一个二进制浮点数可以表示成下面的形式:
 1.    (-1)^S* M* 2个E
 2.    (-1)^s表示符号位,当s=0,V为正数; 当s=1,V为负数

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

  4.    2^E表示指数位。

举例:

9.0    ->  二进制可写为   1001.0 ->  科学技术法表示为    1.001 * 2 ^ 3

则s = 0, M = 1.001, E = 3

 只要能用IEEE754标准写出来的二进制浮点数,只要存储S,M,E即可

float:

c语言进阶 - 数据存储 - 知识点整理_第13张图片

double:

 c语言进阶 - 数据存储 - 知识点整理_第14张图片

 IEEE 754对于M的规定:

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

 IEEE 754对于E的规定:

首先, E 为一个无符号整数( unsigned int
这意味着,如果 E 8 位,它的取值范围为 0~255 ;如果 E 11 位,它的取值范围为 0~2047 。但是,我们知道,科学计数法中的 E 是可以出 现负数的,所以 IEEE 754 规定,存入内存时 E 的真实值必须再加上一个中间数,对于 8 位的 E ,这个中间数 127 ;对于 11 位的 E ,这个中间 数是 1023 。比如, 2^10 E 10 ,所以保存成 32 位浮点数时,必须保存成 10+127=137 ,即 10001001
//浮点数的存储
//int main()
//{
//	float f = 5.5f;
//	//101.1
//	//(-1)^0 * 1.011 * 2^2
//	//s = 0;
//	//M = 1.011
//	//E = 2   + 127 存储
//	// s:0 E:10000001 M:01100000000000000000000
//    //0100 0000 10110000 00000000 00000000
//	//内存中存储为16进制,4个Bit一个十六进制
//	//40 B0 00 00   内存中:0x009BFB2C  00 00 b0 40  小端存储
//}

八、浮点数的取出:

 分为 3 种情况:

E 不全为 0 或不全为 1
这时,浮点数就采用下面的规则表示,即指数 E 的计算值减去 127 (或 1023 ),得到真实值,再将 有效数字 M 前加上第一位的 1
比如:
0.5 1/2 )的二进制形式为 0.1 ,由于规定正数部分必须为 1 ,即将小数点右移 1 位,则为
1.0*2^(-1) ,其阶码为 -1+127=126 ,表示为 01111110 ,而尾数 1.0 去掉整数部分为 0 ,补齐 0 23 00000000000000000000000
则其二进 制表示形式为: 0 01111110 00000000000000000000000
E 全为 0
这时,浮点数的指数 E等于1-127(或者1-1023) 即为真实值,
有效数字 M 不再加上第一位的 1 ,而是 还原为0.xxxxxx的小数 。这样做是为了表示 ±0 ,以及接近于 0 的很小的数字。
比如:+ -  0.001   *  2 ^ (-126)
 
E 全为
这时,如果有效数字 M全为0 ,表示 ± 无穷大(正负取决于符号位 s );
比如:+ -  1. 00   * 2 ^ 128

 

//案例:
int main()
{
	int n = 9;
	float* pFloat = (float*)&n;
	//9 存入计算机内存中为补码:00000000 00000000 00000000 00001001
	//%d打印为有符号整形,9 原反补相同,所以打印为9
	
    printf("n的值为: %d\n",n);//%d 打印为9
	printf("*pFloat的值为:%f\n",*pFloat);
	
    //%f 打印为浮点型,浮点型存储 00000000 00000000 00000000 00001001时,
	//认为S:0 E:00000000 M:00000000000000000001001
	// 取出:
	//当E为全0时:直接就是 1-127 = -126;
	//M: 0.00000000000000000001001
	//(-1)^0 * 0.00000000000000000001001 * 2 ^ -126
	//因为%f默认打印小数点后6位,所以打印0.000000
	

	*pFloat = 9.0;
	//1001.0
	//(-1) ^ 0 * 1.001 * 2 ^ 3
	// S : 0
	// E : 3 + 127 = 130
	// M : 1.001
	// 	   放入内存时:
	// 以浮点数存储:0 10000010 00100000000000000000000
	//%d 认为内存中存储的 0 10000010 00100000000000000000000为二进制补码
	//所以打印为 1091567616
	
    printf("n的值为: %d\n", n);//1091567616
    printf("*pFloat的值为:%f\n", *pFloat);
	
    //以浮点数打印则打印的还是浮点数9.0
	return 0;
}

 

 此篇为本人数据存储章节的课堂笔记整理,如果有误,请在下面留言,感谢支持!

你可能感兴趣的:(【C语言学习】,c语言,开发语言,后端)