C语言之整数_数据存储篇(1)

目录

数据类型

整形家族

浮点型家族

构造类型

指针类型

空类型

整形在内存中的存储(原反补)

NO1.

NO2. 

NO3. 

NO4. 

NO5. 

NO6.

大端小端字节序

NO.1

NO.2

NO.3 

NO.4

练习题

NO1.

NO2.

NO3.

NO4.

NO5.

NO6.

总结 


数据类型

 在初C语言中,我们已经学习过基本内置类型以及它们所占存储空间的大小。我们再回顾一下。

C语言之整数_数据存储篇(1)_第1张图片

C语言之整数_数据存储篇(1)_第2张图片 每一个类型所占空间的大小都不一样,这么多丰富的类型,那它们存在的意义是什么呢?

类型的意义:

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

这样我们就会在合适的场景选择合适的数据类型。 

整形家族

char
      unsigned char
      signed char
short
      unsigned short [int]
      signed short [int]
int
      unsigned int
      signed int
long
      unsigned long [int]
      signed long [int]
long long
//关于long long我们酌情使用。
signed     有符号的
unsigned   无符号的

 为什么char字符会归为整形家族?

字符在内存中的存储的是字符的ASCII码值,ASCII码值是整形。

signed和unsigned 修饰的整形有什么区别吗?

 signed是有符号的;unsigned int 是无符号的。

int a;//== sined int a
signed int a;
unsigned int a;

我们平时在编译器上创建一个变量,相当于创建一个有符号的变量。

当然short   long   long long 均是创建变量相当于创建一个有符号signed 的变量。(除了char)

那char呢?

char是否是相当于signed char?C语言标准并没有规定,取决于编译器。

大部分编译器是,不排除小部分编译器是unsigned int

ASCII码表中规定的ASCII码值的范围是0~127(字符均是正数)。

只有小部分负数是可以存储在 signed char

浮点型家族

float
double

long double
//建议酌情使用

构造类型

//自定义类型
> 数组类型
> 结构体类型 struct
> 枚举类型 enum
> 联合类型 union

指针类型

int *pi;
char *pc;
float* pf;
void* pv;//无具体类型的指针

空类型

 C语言之整数_数据存储篇(1)_第3张图片

void test(void)
//第一个void 表示test函数不会返回任何值
//第二个void 表示test函数没有参数
{
	//
}
int main(void)//
int main(int argc,char* argv[],char* envp[])

整形在内存中的存储(原反补)

 一个变量的创建是要在内存中开辟空间的。空间的大小是根据不同的类型而决定的。

NO1.

那接下来我们来谈谈数据在所开辟内存中到底是如何存储的呢?

计算机能够处理的是二进制的数据。

整型和浮点型数据在内存中也是以二进制的形式进行存储的。

整型在内存中存储的是补码的二进制序列。

NO2. 

 整型的二进制表示形式是怎样的呢?

计算机中的整型有三种二进制表示:原码,反码,补码。

  • 分为有 有符号整数 和 无符号整数。
  • 无符号整数:原码,反码,补码相同。
  • 有符号整数:三种表示方法均有 符号位 和 数值位 两部分。
  • 正数:原码,反码,补码相同。
  • 负数:原码,反码,补码要进行计算的。
  • 符号位:0 表示正
  • 符号位:1 表示负
  • 数值位:正数的原,反,补码相同。
  • 数值位:负数的原,反,补表示方法各不同。

NO3. 

signed int 和 unsigned int? 

 在内存中,对于存储一个整数需要4个字节,也就是32个比特位。

一个整数写出二进制序列的时候,也就是32个比特位。

有符号整数:最高位就是符号位。符号位是1,则表示是负数。符号位是0,则表示是正数

无符号整数:没有符号位,所有位都是数值位。

同一个数无论是有符号整数,还是无符号整数的 数值均相同。

有符号整数的最高位符号位还是会参与运算。

C语言之整数_数据存储篇(1)_第4张图片

 如下:

#include
int main()
{
	int a = 10;//== signed int
	//0 0000000 00000000 00000000 00001010
	unsigned int b =10;
    //00000000 00000000 00000000 00001010
	return 0;
}

站在a的角度,第一个0就是符号位。

站在b的角度,第一个0就是数值位。

NO4. 

负整数的原反补怎样转化呢? 

C语言之整数_数据存储篇(1)_第5张图片

C语言之整数_数据存储篇(1)_第6张图片

C语言之整数_数据存储篇(1)_第7张图片 

NO5. 

进制间的转化?这里我们不专门去讲解,可以自己学一学。

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

  1. 在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号和数值域统一处理。
  2. 同时,加法和减法也可以统一处理(CPU只有加法器)此外,补码和原码相互转换,其运算过程是相同的,不需要额外的硬件电路。

NO6.

#include
int main()
{
	int a = -10;//== signed int
	//1 0000000 00000000 00000000 00001010
	//1 1111111 11111111 11111111 11110101
	//1111 1111 1111 1111 1111 1111 1111 0110——补码
	//十六进制
	//0x ff ff ff f6
	unsigned int b =-10;
    //10000000 00000000 00000000 00001010
	return 0;
}

C语言之整数_数据存储篇(1)_第8张图片

整形在内存中是以二进制的补码存储的,在编译器中为了观瞻,是以十六进制的方式去展示给我们,请问为什么是以十六进制倒叙放置的呢?那接下来我们就要介绍我们的大小端字节序存储。

大端小端字节序

关于内存中二进制/十六进制,单位 比特位和字节的转换,如下图。

C语言之整数_数据存储篇(1)_第9张图片

NO.1

大端小端产生?

int a=0x11223344
//1 2 3
//百位 十位 各位
//高位      低位

C语言之整数_数据存储篇(1)_第10张图片

根据字节存储来解释。

我们可以有无数中存储方式,只要按照存进去的方式,在需要使用时拿出来按照原来的顺序放置还原。怎么存都可以!

但是为了简便我们只采用了两种存储方式:

  • 大端字节序存储:把一个数据的低位字节序的数据存放在内存的高地址处,高位字节处的数据存放在内存的低地址处。
  • 小端字节序存储:把一个数据的高位字节序的数据存放在内存的低地址处,高位字节处的数据,存放在内存的高地址处。

除了字符整型,都是这两种存储方式,char1个字节不需要顺序。

NO.2

什么是大端小端?

NO.3 

为什么有大端小端?

C语言之整数_数据存储篇(1)_第11张图片

NO.4

笔试题:请简述大端字节序和小端字节序的概念,设计一个小程序来判断当前机器的字节序?

 C语言之整数_数据存储篇(1)_第12张图片

根据上图就有如下代码:

#include
int main()
{
	int a = 1;//
	char* p = (char*)&a;//强制转化
	if (*p == 0)
		printf("大端\n");
	if(*p == 1)
		printf("小端\n");
	return 0;
}
//用函数包装呢?
#include
int check_sys(void)
{
	int a = 1;
	char* p =(char*) &a;//强制类型转化
	if (*p == 0)
		return 0;
	if (*p == 1)
		return 1;
}
int main()
{
	int ret = check_sys();
	if (ret == 0)
		printf("大端\n");
	if (ret == 1)
		printf("小端\n");
	return 0;
}

//简化
#include
int check_sys()
{
	int a = 1;
	return *(char*)&a;
}
int main()
{
	int ret = check_sys();
	if (ret == 0)
		printf("大端\n");
	if (ret == 1)
		printf("小端\n");
	return 0;
}

练习题

//以下主要讲解的是char类型的signed 和unsigned 
//可以推广到short/long等等
%d 是十进制的形式打印有符号整数
%u 是十进制的形式打印无符号整数

NO1.

请问下面程序a,b,c分别是多少? 

1.
//输出什么?
#include 
int main()
{
  char a= -1;
  signed char b=-1;
  unsigned char c=-1;
  printf("a=%d,b=%d,c=%d",a,b,c);
  return 0;
}

#include 
int main()
{
	char a = -1;
	//有符号的 负数 char类型
	// 10000000 00000000 00000000 00000001原码
	// 11111111 11111111 11111111 11111110反码
	// 11111111 11111111 11111111 11111111补码
	//存储char  11111111补码
	signed char b = -1;
	//有符号的 负数  char类型同上
	//存储char  11111111补码
	unsigned char c = -1;
	//无符号的  负数  char类型
	//无符号——没有符号位的概念
	// 无符号整数一般放置正数,如果放置负数还是按照负数的原反补来计算
	// 10000000 00000000 00000000 00000001原码
	// 01111111 11111111 11111111 11111110反码
	// 01111111 11111111 11111111 11111111补码
	// 存储char 11111111补码
	//存储char  11111111
	printf("a=%d,b=%d,c=%d", a, b, c);
	//%d 是十进制的形式打印有符号整数
	// 即便没有符号,当作有符号去打印
	//整型提升
	// 有符号位提升符号位
	// 无符号位补0,提升0
	// 有符号ab
	//11111111 11111111 11111111 11111111补码
    //10000000 00000000 00000000 00000001原码
	//打印-1
	//b同理-1
	//无符号c
	//1111111
	//00000000 00000000 00000000 11111111补码原码反码
	//正数的原码反码补码相同
	//打印-c
	//225
	return 0;
}

NO2.

 请问下面三端程序分别输出什么?

2.
#include 
int main()
{
char a = -128;
printf("%u\n",a);
return 0;
}
//
#include 
int main()
{
char a = 128;
printf("%u\n",a);
return 0;
}
//
#include 
int main()
{
char a = 384;//128+256
printf("%u\n",a);
return 0;
}
//2.
#include 
int main()
{
	char a = -128;
	//有符号整型 char 负数
	//10000000 00000000 00000000 10000000原码
	//11111111 11111111 11111111 01111111反码
	//11111111 11111111 11111111 10000000补码
	//存储a char        10000000
	printf("%u\n", a);
	//%u 是十进制打印无符号整型
	//整型提升——变量的类型(有符号/无符号)
	//1111111 111111111 11111111 10000000补码
	// 打印——看(u/d)——(u_原反补相同/d_正原反补相同_负的计算)
	//%u把a看成无符号整数
	// 1就不是a的符号位了
	//打印
	//无符号整型原反补相同
	//4,294,967,168
	return 0;
}
//
#include 
int main()
{
	char a = 128;
	//原反补相同
	//00000000 00000000 00000000 10000000补码
	//存储     10000000
	printf("%u\n", a);
	//提升     11111111 11111111 11111111 10000000补码
	//打印——看成无符号的——原反补相同
	//所以还是同上
	return 0;
}

经过我们计算和分析,发现上面三段 代码输出的结果是一样的。why?

  • 有符号的char类型(signed char)取值范围:-128~127
  • 无符号的char类型(unsigned char)取值范围:0~225
  • 截断:超过以上的范围,有一部分数据会被截断,只要存储在内存中的数据必须是在以上范围内。

NO3.

 请问下面这段代码输出什么?

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

//按照补码的形式进行运算,最后格式化成为有符号整数

#include
int main()
{
int i = -20;
//10000000 00000000 00000000 00010100
//11111111 11111111 11111111 11101011
//11111111 11111111 11111111 11101100补码
unsigned int j = 10;
//00000000 00000000 00000000 00001010原反补相同
printf("%d\n", i + j);
//11111111 11111111 11111111 11110110补码
//10000000 00000000 00000000 00001010原码
//-10
return 0;
}

NO4.

下面这段代码输出什么? unsigned int的范围

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

NO5.

 下面这段代码输出什么?signed char的范围

5.
int main()
{
char a[1000];
int i;
for(i=0; i<1000; i++)
{
a[i] = -1-i;
}
printf("%d",strlen(a));
return 0;
}

NO6.

 下面这段代码输出什么?unsigned char的范围

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

总结 

C语言之整数_数据存储篇(1)_第13张图片

有符号整型signed char 

 C语言之整数_数据存储篇(1)_第14张图片

 无符号整型unsigned int

C语言之整数_数据存储篇(1)_第15张图片

  •  有符号整型signed char的取值范围:127 ~  -128
  • 无符号整型unsigned char的取值范围:0~255

同理我们可以将以上代码应用于其他整型short/int/long等等。总结出它们的取值范围。特别注意千万别掉进无符号整型的陷阱了!!

例如:short两个字节 16个比特位

  • 有符号整型signed short的取值范围:-32768~32767
  • 无符号整型unsigned short的取值范围:0~65635

同理大家自己动手总结一下整型类型的取值范围。

关于浮点数的存储会在下篇博文讲解,同时也会去总结二进制中的知识和易错混点。

✔✔✔✔最后,感谢大家的阅读,若有错误和不足,欢迎指正。

代码-----------------→【gitee:https://gitee.com/TSQXG】

联系-----------------→【邮箱:[email protected]

你可能感兴趣的:(c语言,开发语言)