C语言_数据的存储
创始人
2024-12-27 11:33:49
0

目录

数据类型介绍

整形在内存中的存储

浮点型在内存中的存储


数据类型介绍

1. 整形家族

//字符存储的时候,存储的是ASCII值,是整型

//char 默认是unsigned char还是signed char标准没有规定,其他类型都默认是signed

char,unsigned char,signed char

short,unsigned short

int,unsigned int

long,unsigned long

关于char的取值范围 

signed char

unsigned char

2. 浮点数家族

float

double

long double

3. 构造类型(自定义类型)

数组类型

结构体类型 struct

枚举类型 enum

联合类型 union

4. 指针类型

int* pi;

char* pc;

float* pf;

void* pv;

结构体的指针

...

5. 空类型

void 表示空类型(无类型)

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


整形在内存中的存储

1. 原码、反码、补码

1. 计算机中的整数有三种2进制表示方法,即原码、反码和补码。

2. 三种表示方法均有符号位和数值位两部分,最高位是符号位,符号位都是用0表示“正”,用1表示“负”。

3. 正整数的原、反、补码都相同。

4. 负整数的三种表示方法各不相同,

原码:直接将数值按照正负数的形式翻译成二进制就可以得到原码。

反码:将原码的符号位不变,其他位依次按位取反就可以得到反码。

补码:反码+1就得到补码。

下面是原反补例子

int num = 10; //创建一个变量叫num,num向内存申请4个字节来存放数据 //4个字节是32个比特位 //00000000 00000000 00000000 00001010 原码 //00000000 00000000 00000000 00001010 反码 //00000000 00000000 00000000 00001010 补码  int num2 = -10; //10000000 00000000 00000000 00001010 原码 //11111111 11111111 11111111 11110101 反码 //11111111 11111111 11111111 11110110 补码

对于整形来说:数据存放内存中其实存放的是补码。为什么呢?

在计算机系统中,数值一律用补码来表示和存储。

原因在于使用补码可以将符号位和数值位统一处理,

同时,加法和减法也可以统一处理(CPU只有加法器)

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

·

一个例子讲述为什么要补码,因为有些东西原码算不了

计算1 - 1 也就是1 + (-1)

原码计算

00000000 00000000 00000000 00000001     1的原码

10000000 00000000 00000000 00000001    -1的原码

10000000 00000000 00000000 00000010    相加后等于-2 

·

下面是补码计算

00000000 00000000 00000000 00000001     1的补码

11111111   11111111   11111111  11111111       -1的补码

00000000 00000000 00000000 00000000     相加后的等于0

2. 大小端介绍

什么是大端小端?

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

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

 为什么有大端和小端?

这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit。但是在C语言中除了8 bit的char之外,还有16 bit的short型,32 bit的long型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。

 设计一个函数来判断当前机器的字节序。

//思路:利用char*只访问第一个字节来判断差异 //只能输入1,返回1是小端,0是大端 int check(int a) { return *(char*)&a; }  int main() { 	if (check(1)) printf("small\n"); // 01 00 00 00 	else printf("big\n"); //00 00 00 01     	return 0; }

3. 练习 

1.

//输出什么? #include  int main() {     signed char b = -1;     unsigned char c = -1;     printf("b=%d,c=%d",b,c);     return 0; }  //10000000 00000000 00000000 00000001  -1的原码,然后要转补码 //11111111 11111111 11111111 11111111  -1的补码 //11111111  补码存进char里,从低位开始截断  //b, c存放的都是11111111,%d是十进制形式打印有符号整型,所以需要整型提升 //11111111 11111111 11111111 11111111 b有符号类型符号位补齐, 然后转原码得-1 //00000000 00000000 00000000 11111111 c无符号类型高位补0,正数原反补相同  

2.

#include  int main() {     char a = -128;     printf("%u\n",a);     return 0; }  //首先算出a的原码 //10000000 00000000 00000000 10000000 //将原码转成补码 //11111111 11111111 11111111 10000000 //存入char所以发生截断 //10000000 //%u - 按无符号整型打印,所以需要整型提升 //因为a的数据类型有符号所以符号位补齐 //因为%u, 所以直接当正数,原反补相同 //11111111 11111111 11111111 10000000

3.

#include  int main() {     char a = 128;     printf("%u\n",a);     return 0; }  //一般的步骤,1.算出原码,2.转成补码,3.截断,4.整型提升,5.按要求打印 //00000000 00000000 00000000 10000000 原码, 补码 //10000000 截断 //11111111 11111111 11111111 10000000 整型提升,因为类型是char所以符号位补齐

4.

int i = -20; unsigned int j = 10; printf("%d\n", i+j);  //11111111 11111111 11111111 11101100 i的补码 //00000000 00000000 00000000 00001010 j的补码 //11111111 11111111 11111111 11110110 i+j 补码相加, 然后转原码打印

5.

unsigned int i; for(i = 9; i >= 0; i--) {     printf("%u\n",i); }  //unsigned int 导致i不会小于0所以死循环

6.

int main() {     char a[1000];     int i;     for(i=0; i<1000; i++)     {         a[i] = -1-i;     }     printf("%d",strlen(a));     return 0; }  //解析: //1.这个for循环1000次,i从0到999 //2.可以得出a[i]等于-1,-2,-3,... //3.又因为每个元素是char类型,char的范围是-128到127 //4.所以真实存放的样子,-1,-2,-3,... -128,127,126,... 3 2 1 0 //5.strlen统计\0之前的字符个数,\0的ASCII值是0

7.

#include  unsigned char i = 0; int main() {     for(i = 0;i<=255;i++)     {         printf("hello world\n");     }     return 0; }  //死循环,因为unsigned char范围就是0到255

浮点型在内存中的存储

1. 浮点数存储规则

根据国际标准,任意一个二进制浮点数 V 可以表示成这个形式:(-1)^S * M * 2^E

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

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

3. 2^E表示指数位。

 例子

IEEE 754 规定: 

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

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

IEEE 754 对有效数字M有一些特别规定。

1. 前面说过,1≤M<2,也就是说,M可以写成 1.xxxxxx 的形式,其中xxxxxx表示小数部分。

2. 默认M的第一位总是1,因此可以被舍去,只保存后面的xxxxxx部分。

3. 比如保存1.01的时候,只保存01,等到读取的时候,再把第一位的1加上去。

4. 这样做的目的是节省1位有效数字。

·

IEEE 754 对指数E有一些特别规定。

1. 首先,E是一个无符号整数(unsigned int)

2. 这意味着,如果E为8位,它的取值范围为0~255;如果E为11位,它的取值范围0~2047。

3. 但是,科学计数法中的E是可以出现负数的

4. 所以IEEE 754规定,存入内存时E的真实值必须再加上一个中间数,对于8位的E,这个中间数是127;对于11位的E,这个中间数是1023。

5. 。比如,2^10的E是10,所以保存成32位浮点数时,必须保存成10+127=137,即 10001001。

·

然后,指数E从内存中取出还可以再分成三种情况:

1. E不全为0或不全为1,这时,指数E的计算值减去127(或1023)得到真实值,再将有效数字M前加上第一位的1。

2. E全为0,这时指数E等于1-127(或者1-1023)即为真实值, 有效数字M不再加上第一位的1。

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

2. 一个浮点数存储的例子

//输出什么? int main() {     int n = 9;     float *pFloat = (float *)&n;      printf("n的值为:%d\n",n); //9     printf("*pFloat的值为:%f\n",*pFloat); //0.000000      *pFloat = 9.0;     printf("n的值为:%d\n",n); //1091567616     printf("*pFloat的值为:%f\n",*pFloat); //9.000000      return 0; }  //算出9的二进制序列 //00000000 00000000 00000000 00001001 //当作浮点数存储就变成 //0 00000000 00000000000000000001001 //S     E              M  //算出9.0二进制序列 //1001.0 //转化 //(-1)^0 * 1.001 * 2^3 //所以S = 0, M = 1.001, E = 3 //0 10000010 01100000000000000000000 //S     E               M

练习题

答:D


 

答:C

解析:1.补码,2.整型提升,3.截断


 

答:B


 

答:A


 

//思路:1.先用5层循环把所有情况列一遍 //2.说对了一半意味着一个为真一个为假,1+0=1 int main() { 	for (int a = 1; a <= 5; a++) 	{ 		for (int b = 1; b <= 5; b++) 		{ 			for (int c = 1; c <= 5; c++) 			{ 				for (int d = 1; d <= 5; d++) 				{ 					for (int e = 1; e <= 5; e++) 					{ 						if ((b == 2) + (a == 3) == 1 							&& (b == 2) + (e == 4) == 1 							&& (c == 1) + (d == 2) == 1 							&& (c == 5) + (d == 3) == 1 							&& (e == 4) + (a == 1) == 1 							&& a*b*c*d*e == 120) 						{ 							printf("a:%d b:%d c:%d d:%d e:%d\n", a, b, c, d, e); 						} 					} 				} 			} 		} 	}  	return 0; }

 

int main() { 	//因为凶手只有一个,所以就一次假设一个凶手进行遍历 	for (char killer = 'a'; killer <= 'd'; killer++) 	{ 		if ((killer!='a') + (killer=='c') + (killer=='d') + (killer!='d') == 3) 		{ 			printf("%c\n", killer); 			break; 		} 	} }

int main() { 	int n; 	scanf("%d", &n); 	int arr[10][10] = { 0 }; 	//遍历赋值 	for (int i = 0; i < n; i++) 	{ 		for (int j = 0; j <= i; j++) 		{ 			//第一列和对角线都是1 			if (j == 0 || i == j) arr[i][j] = 1; 			else arr[i][j] = arr[i - 1][j] + arr[i - 1][j - 1]; 		} 	} 	//遍历输出 	for (int i = 0; i < n; i++) 	{ 		for (int j = 0; j <= i; j++) printf("%d ", arr[i][j]); 		printf("\n"); 	} 	return 0; }

相关内容

热门资讯

root后开启指纹支付,roo... ROOT后,微信,支付宝指纹支付可以用吗若是支付宝或微信支持手机的指纹支付功能的话,是可以开启的,不...
William Yang:从区... 在区块链技术和加密货币市场飞速发展的今天,William Yang无疑是这一领域的佼佼...
BTC链/ETH链/TRC链/... 智能合约代码 智能合约是一种在区块链上运行的代码,它定义了资产的所有权变更、交易的...
香港阿里云代理商:阿里区块链仓... 香港阿里云代理商:阿里区块链仓单有什么用简介: 飞机@luotu...
第七个了解!wepoKER外挂... 第七个了解!wepoKER外挂辅助器脚本,wpk微扑克有辅助插件的(有挂细节)-哔哩哔哩;科技安装教...
python+flask计算机... 本系统(程序+源码+数据库+调试部署+开发环境...
Milvus 实践(1) --... 目录背景训练素材downloadtorchvision 简介python代码执行结果模型训练模型训练...
8分钟秒懂!吉利比鸡辅助!(透... 自定义新版吉利比鸡辅助系统规律,只需要输入自己想要的开挂功能,一键便可以生成出吉利比鸡辅助专用辅助器...
第九实锤!wepoke科技外挂... 第九实锤!wepoke科技外挂透明挂辅助器插件,wepoke辅助(有挂技巧)-哔哩哔哩;德扑锦标赛是...
wonder trader c... WonderTrader是一个基于C++核心模块的,适应全市场全品种交...