【C语言进阶】数据的存储【上篇】【万字总结】

  作者:你我皆为凡人

 博客主页:你我皆为凡人的博客

 名言警句:时间不会为任何人停留,而事物与人,无时不刻也在变化着。每一个人,也都在不停向前!

 觉得博主文章写的不错的话,希望大家三连(✌关注,✌点赞,✌评论),多多支持一下!!

 系列作品:

 

 C语言编程刷题篇

 经典题型系列

 【C语言进阶】数据的存储【上篇】【万字总结】_第1张图片

文章目录

目录

文章目录

前言

数据类型的介绍

整形在内存中的存储

原码,反码,补码

大小端介绍

一道经典笔试题

巩固练习

练习一

练习二

练习三

练习四

练习五

练习六

练习七

习题练习入口


前言

本文重点讲解了数据类型的详细介绍与在内存中存放的数值,整形在内存中的存储以及原码反码补码的详细介绍,大小端字节序介绍及其判断,以及7道经典的题型让大家得以巩固知识


提示:以下是本篇文章正文内容,下面案例可供参考

数据类型的介绍

前面我们已经学习了基本的内置类型:

#include
int main()
{
	    char    1字节    //字符数据类型     
		short   2字节    //短整型 
		int     4字节    //整形
		long    4/8字节    //长整型
		long long  8字节 //更长的整形
		float    4字节   //单精度浮点数
		double   8字节   //双精度浮点数
	return 0;
}

 类型的意义:

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]
浮点数家族:
float
double
构造类型:
 数组类型
 结构体类型 struct
 枚举类型 enum
 联合类型 union
指针类型:
int *pi;
char *pc;
float* pf;
void* pv;
空类型:
void 表示空类型(无类型)
通常应用于函数的返回类型、函数的参数、指针类型

整形在内存中的存储

int main()
{
	int a = 20;
	int b = -10;
	return 0;
}

 我们之前了解过一个变量的创建是要在内存中开辟空间的,空间大小是根据不同的类型而创建的,那么接下来我们谈谈数据在所开辟的内存中到底是如何存储的,比如上面的代码,我们知道a和b分配4个字节的空间,那么是如何存储的呢?

原码,反码,补码

整数可以用二进制,十进制,十六进制,八进制表示,而在内存中是用二进制来展示,而整数的二进制表示有三种表示,原码,反码与补码

三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位用0或者1表示

对于负整数的三种表示方法各不相同:

原码:

直接将整数按照正负数的形式表示成二进制就可以

反码:

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

补码:

反码+1就得到补码

正数的原,反,补码都相同

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

 所以上图的代码在内存中的存储就是这样的:

int main()
{
	int a = 20;
	//20   正数
	//00000000000000000000000000010100  原码
	//00000000000000000000000000010100   反码
	//00000000000000000000000000010100   补码
	int b = -10;
	//-10   负数
	//10000000000000000000000000001010 原码
	//11111111111111111111111111110101 反码
	//11111111111111111111111111110110 补码
	return 0;
}

 二进制在内存中存储是32位比特位,太长了,一般在内存中以十六进制储存

那么转变过来就是:

int main()
{
	int a = 20;
	//20   正数
	//00000000000000000000000000010100  原码
	//0x00000014
	//00000000000000000000000000010100   反码
	//0x00000014
	//00000000000000000000000000010100   补码
	//0x00000014
	int b = -10;
	//-10   负数
	//10000000000000000000000000001010 原码
	// 0x800000a
	//11111111111111111111111111110101 反码
	// 0xffffff5
	//11111111111111111111111111110110 补码
	//0xfffffff6
	return 0;
}

 可是在内存中具体存放的是哪一个呢?正数的原码反码补码都相同,可是负数的原码反码与补码到底存放的是哪一个呢?接下来就明白了:

【C语言进阶】数据的存储【上篇】【万字总结】_第2张图片

【C语言进阶】数据的存储【上篇】【万字总结】_第3张图片

 我们根据在内存中观察到的十六进制发现存放着的是补码

那么为什么呢?

在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统 一处理;
同时,加法和减法也可以统一处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。
其实意思就是:
1-1在计算机中会转换成1+(-1)那么如何计算呢?
00000000000000000000000000000001    1
10000000000000000000000000000001    -1
如果原码相加:
10000000000000000000000000000010    -2   结果是错误的,无法计算
如果补码相加:
00000000000000000000000000000001    1的补码  
1111111111111111111111111111111111111    -1的补码
相加结果:
100000000000000000000000000000000    成为了33位比特位,而首位会丢弃,所以为0
而补码与原码相互转换其运算过程是相同的,原码可以取反得到反码,反码+1得到补码,而同样,补码可以-1得到反码,反码取反回到原码,但是还可以补码取反+1得到原码
比如:
-10
11111111111111111111111111110110   
1000000000000000000000001001    
1000000000000000000000001010

大小端介绍

我们可以得出结论a与b分别存储的是补码,但是顺序好像有点不对劲,是反着来的,那么这又是为什么,这就涉及到大小端的概念了

什么是大端小端呢?:

大端【字节序】(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;
小端【字节序】(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位,,保存在内存的高地址中;
而在上面我们可以看到,内存中存放着是小端存储
可是为什么会有大端和小端呢:
为什么有大端和小端:
为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8 bit。但是在C语言中除了8 bit的char之外,还有16 bit的short型,32 bit的long型(要看具体的编译器),另外,对于位数大于8位 的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。
例如:一个 16bit 的 short 型 x ,在内存中的地址为 0x0010 , x 的值为 0x1122 ,那么 0x11 为 高字节, 0x22 为低字节。对于大端模式,就将 0x11 放在低地址中,即 0x0010 中, 0x22 放在高地址中,即 0x0011 中。小端模式, 刚好相反。我们常用的 X86 结构是 小端模式,而 KEIL C51 则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以 由硬件来选择是大端模式还是小端模式

一道经典笔试题

这是一道百度2015年系统工程师笔试题

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

如1这个数字,无非就是  0x 00 00 00 01 与0x 01 00 00 00 这两种方式,区别在于第一个字节是否相同,那么如果我们取地址这个数是4个字节,那么强制转换为char类型就是1个字节,刚好是01或者00,而01就是1,00就是0,来进行判别

int main()
{
	int a = 1;
	if (*(char*)(&a) == 1)
	{
		printf("小端\n");
	}
	else
	{
		printf("大端\n");
	}
	return 0;
}

巩固练习

练习一

//输出什么?
#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; 
}

 现在我们储备一些知识,那么就是如果一个char类型的数值,在内存中有有符号与无符号之分,那么有符号在内存中存放的最大数值为127到-128之内,无符号在内存中存放的最大数值为0-255,那么short类型的呢?如果是无符号在内存中存放的最大数值为0到65535,如果是有符号在内存中存放的最大数值为-32768到32767,而其他的也可以按照二进制而推算出来

解析:

a的值是-1,存放到char类型中但是要以整形打印,-1的二进制为10000000000000000000000000000001   -1的源码

1111111111111111111111111111111111110   -1的反码

1111111111111111111111111111111111111   -1的补码

但是char类型中只能存放1个字节,就是8个比特位,发生了截断

11111111    a的值

%d的打印有符号的整形,所以要整型提升,有符号char根据符号位补齐

1111111111111111111111111111111111111    a的补码,但是打印的是源码

10000000000000000000000000000000   

10000000000000000000000000000001   a的源码,也就是最后打印的数值 -1

同理,b的也是有符号char,所以也是-1

c是个无符号char,而无符号char在内存中只能存放0到255,那么如何存放-1呢?

10000000000000000000000000000001    -1的源码

1111111111111111111111111111111111110    -1的反码

1111111111111111111111111111111111111    -1的补码

截断:

11111111    

注意无符号的char  整型提升直接补0

000000000000000000000000011111111   补码

而整数的正数原反补都相同,所以打印出来的数为255

练习二

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

 char的取值范围在-128到127之间,而a的值在这个范围内,是有符号的char,而要以无符号类型打印出来

 10000000000000000000000010000000   -128原码

 111111111111111111111111111101111111  -128反码

1111111111111111111111111111110000000   -128补码

截断放入char a中

10000000   -a

整型提升,无符号直接打印1

11111111111111111111111110000000     a的值是一个非常大的数值  4,294,967,168

练习三

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

 char的128不在char范围内,先写出原码

10000000000000000000000010000000

截断到char中

10000000     

无符号打印,要整形提升,直接写1

11111111111111111111111110000000    a的值最后也是一个非常大的数值   4,294,967,168

练习四

int i= -20;
unsigned  int  j = 10;
printf("%d\n", i+j); 
//按照补码的形式进行运算,最后格式化成为有符号整数

 i是整数的-20

10000000000000000000000000010100   -20的原码

11111111111111111111111111101011    -20的反码

11111111111111111111111111101100    -20的补码

j是无符号整数10

00000000000000000000000000001010  10的补码

整数形式打印i+j

11111111111111111111111111101100     -20的补码

00000000000000000000000000001010  10的补码

相加后的结果:

11111111111111111111111111110110    相加后的补码

10000000000000000000000000001001   反码

10000000000000000000000000001010   最后的补码    打印的结果就是-10

练习五

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

 定义i是一个无符号的整数,i为9,从9打印到0,然后0-1为-1,而无符号是没有负数的存在的,-1的补码是全1,这是一个很大的数字,往后会是一直打印死循环

练习六

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

 char数组里存放1000个元素,a【i】= -1-i;可能我们会想,那么最后的数字不就是-1,-2,-3.。。。到-1000,一千个数嘛   而strlen是求字符串的长度,关注的是字符串中\0(数字0)之前出现过多少字符,而这里面没有\0和数字0,所以是1000,这样想就大错特错了,char的取值范围是-128-127,从-1到-128,下一个会是127-0,那么-128到127之间会有255个数值所以答案是255

练习七

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

 定义一个无符号的char类型的i,i小于等于255,要跳出循环得是256,但是无符号char类型的i最大的存储数值为0到255,所以永远不会成为256,所以是死循环

习题练习入口

看完这些不具体操作操作那么是不可以的,可以点击上方直达去练习一些有关习题,也可以随便看一看C语言的一些习题,练习练习选择题和编程题,让自己的知识得到巩固,直接点入标题就可直达,另外想获得大厂内推资格也可以去看看:

大厂内推

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