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

  💘作者:你我皆为凡人

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

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

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

 💘系列作品:

 💘

 💘C语言编程刷题篇

 💘经典题型系列

 

文章目录

目录

文章目录

🙈 前言

💫数据类型的介绍

💫整形在内存中的存储

💘 原码,反码,补码

💘 大小端介绍

💘 一道经典笔试题

💘 巩固练习

💨练习一

💨练习二

💨练习三

💨练习四

💨练习五

💨练习六

💨练习七

💞习题练习入口


🙈 前言

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


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

💫数据类型的介绍

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

#include<stdio.h>
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;
}

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

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

那么为什么呢?

在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统 一处理;
同时,加法和减法也可以统一处理(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 <stdio.h>
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 <stdio.h>
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 <stdio.h>
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 <stdio.h>
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语言的一些习题,练习练习选择题和编程题,让自己的知识得到巩固,直接点入标题就可直达,另外想获得大厂内推资格也可以去看看:

大厂内推


原文连接:https://blog.csdn.net/weixin_45659943/article/details/124976131

相关推荐

【Linux系统编程:基础IO 壹】简单复习C语言文件接口 | 学习系统文件接口 | 认识文件描述符 | Linux下,一切皆文件 | 重定向原理

C语言自定义类型篇——自定义类型:结构体,枚举,联合

C语言——三种方式实现学生信息管理

【C】文件操作进阶知识

【c ++ primer 笔记】第8章 IO库

带你刷(牛客网)C语言百题(第二天)

TCP的粘包问题代码说明

【C语言】文件操作详解

【C语言】动态内存管理

C语言文件篇——文件操作

【C语言进阶】自定义类型——结构体

【深入理解C】动态内存管理

数学建模国赛 2020B-穿越沙漠 第一关 Lingo 和 C语言 动态规划求解

【C】柔性数组

全面解析C语言多媒体开源框架GStreamer

Python究竟属不属于嵌入式语言?

C/C++牛客网刷题练习之翻转链表篇

非递归算法——快速排序、归并排序

【C语言】静态&动态&文件通讯录(超万字)

C语言进阶——自定义类型:结构体 枚举 联合