【C语言】-深入内存带你看数据的存储

news2024/11/16 17:58:03

🎇作者:小树苗渴望变成参天大树
🎉 作者宣言:认真写好每一篇博客
🎊作者gitee:link
在这里插入图片描述
如 果 你 喜 欢 作 者 的 文 章 ,就 给 作 者 点 点 关 注 吧!

数据的存储

  • 🧨 前言
  • ✨一、数据类型的详细介绍
    • 💖1.1类型的基本分类
  • 💨二、整形在内存中的存储(limits.h)
    • 💢2.1原码、反码、补码
    • 💥2.2大小端介绍
    • 💤2.3练习
  • 三、浮点型在内存中的存储(float.h)
    • 💦3.1一个例子
    • 🎞️3.2浮点数存储规则
  • 💞四、总结


🧨 前言

Hello,各位小伙伴们,好久不见。之前由于学校的考试,耽误了更新好的文章了,最近也是才回家没多久,想着尽快给友友们传递更多有用的知识,让大家久等了。
今天我们来讲点不一样的东西,我们的电脑也叫计算机,是帮助我们计算数据的,那计算机时怎么获取我们所想要计算的数据呢?这就是涉及到数据怎么在计算机里面存储的,只有把数据存在计算机里,它才能拿数据去计算,来达到我们想要的结果,所以我们这篇博客就会详细的介绍数据怎么在计算机里面存储的,让我们一起进入正文!!
本篇重点

  1. 数据类型详细介绍
  2. 整形在内存中的存储:原码、反码、补码
  3. 大小端字节序介绍及判断
  4. 浮点型在内存中的存储解析

✨一、数据类型的详细介绍

我们之前学习了许多类型,并且知道了他们占用了多大的空间,例如:

char //字符数据类型–1个字节
short //短整型–2个字节
int //整形–4个字节
long //长整型–4/8个字节
long long //更长的整形–4/8个字节
float //单精度浮点数–4/8个字节
double //双精度浮点数–4/8个字节

我们之所以要介绍数据类型是因为,我们把数据放到内存中,要开启自己的空间来存放数据,而类型的意义就在于开辟了多大的内存空间让我们来存放数据,并且决定了使用的范围和如何看待内存空间的视角。

💖1.1类型的基本分类

通过以上的数据类型,我们可以把数据类型分成两类
一.整型家族

char
unsigned char
signed char
那为什么字符型char有放在整型家族里面呢?
因为字符在存储的时候存储的是ASCII码,ASCII码是整数,所以当成整型家族的类型了。

short
unsigned short [int] = unsigned short
signed short [int]=signed short=short

int
unsigned int
signed int

long
unsigned long [int]=unsigned long
signed long [int]=signed long= long

long long
unsigned long long [int]=unsigned long long
signed long long [int]=signed long long=long long

unsinged是表示无符号的类型(都是正数),signed是表示有符号的类型(有正有负),=意思为等价的,但是 char不一定等价于signed char,因为char不知道是unsigned char,还是signed char,这个取决于编译器,大部分的时候还是等价的,但是避免出现错误,我们还是养成习惯加上signed或者unsigned;
二.浮点数家族

float
double
浮点数就是带有小数点的数,不是整数,这两个等会在具体介绍。

三.构造类型

数组类型
int a[10]; --他的数据类型是int [10].随着元素个数或者类型的改变,数组的类型也会改变,所以说这是我们构造出来的类型

结构体类型 struct
枚举类型 enum
联合类型 union
这三个我会在后期的博客详细的介绍他们是什么,并且为什么是构造类型和怎么去使用,相信那个时候你就会理解这些类型了

四.指针类型

int pi;
char pc;
float
pf;
void
pv;
我们在指针那篇博客中也详细介绍了什么是指针类型,指针类型表示指针的步子有多长,一步能访问几个字节,这个在一会要讲的大小端会用到,不会的可以先看一下我那篇讲解指针的博客

五.空类型

void 表示空类型(无类型)
通常应用于函数的返回类型、函数的参数、指针类型
void f(voif)表面函数的返回类型是void,强调了不需要参数用void

说了这么多类型的分类,主要就是让大家更好的理解数据类型,但数据在内存中的存储就分为两种,一个是整型的存储方式,一个是浮点数的存储方式,那我们接下来就来重点介绍着两个存储方式。

💨二、整形在内存中的存储(limits.h)

我们刚才讲过一个变量的创建是要在内存中开辟空间的。空间的大小是根据不同的类型而决定的。
例:

int a = 20;
int b = -10;

我们是把数据放到int类型的变量里面,所以为我们开辟了四个字节的空间内,一个字节是八个比特位,所以我们将用三十二个比特位来存储数据。

我们既然知道为 a 分配四个字节的空间。
那如何存储?
那接下来就要理解三个概念。

💢2.1原码、反码、补码

计算机中的整数有三种表示方法,即原码、反码和补码。
三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位转换成对应的二进制数。
因为我在详解操作符那篇博客也详细介绍过这几个概念,所以这里我就直接写结果了。
一.正数

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

二.负数

原码:
直接将二进制按照正负数的形式翻译成二进制就可以。
反码:
将原码的符号位不变,其他位依次按位取反就可以得到了。
补码:
反码+1就得到补码。

int a = 20;
//00000000 00000000 00000000 00010100 原码
//00000000 00000000 00000000 00010100 反码
//0000 0000 0000 0000 0000 0000 0001 0100 补码
    0   0     0    0    0    0   1     4  补码的十六进制表示
00 00 00 14
int b = -10;
//10000000 00000000 00000000 00001010 原码
//11111111 11111111 11111111 11110101 反码
//1111 1111 1111 1111 1111 1111 1111 0110 补码
    f    f    f    f    f    f    f    6  补码的十六进制表示
ff ff ff f6

//并且两个十六进制表示一个字节

那让我们看看内存里到底是怎么存放的??
在这里插入图片描述
我们看到是存放的十六进制的数,原因是他是以十六进制的形式展示在内存窗口中,并且以字节为一个单位,如果以二进制的形式展示,那么就没有这么大的窗口给你看。

但结果和我们计算出来的又有点差别,我们发现他是倒着存放的,着就要涉及倒我接下来要讲的大小端存储模式了,但我们至少知道整型在内存中是以补码的形式存放的,至于按照什么顺序存放我们先不要管。

思考
为什么在内存中我们要使用补码来存储数据呢??,用原码或者反码不行吗??
我们来举个例子看看:

int a=-20;
int b=10;
int c=a+b;求c
a
//10000000 00000000 00000000 00010100--原码
b
//00000000 00000000 00000000 00001010--原码
c
//10000000 00000000 00000000 00011110--原码
结果为-30;答案是错误的
a
//11111111 11111111 11111111 11101011--反码
//11111111 11111111 11111111 11101100--补码
b
//00000000 00000000 00000000 00001010--反码
//00000000 00000000 00000000 00001010--补码
c
//11111111 11111111 11111111 11110110--补码
补码取反加1得原码
//10000000 00000000 00000000 00001010--原码
答案是-10;是正确的

读者可以自己找一些数字来验证一下。
在这里插入图片描述
那为什么要使用补码和为什么补码有这样作用?

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

我们从计组的角度来跟大家解释一下为什么要使用补码,并且为什么补码是那样计算出来的?
一.我们刚才说了在计算机中我们只有加法器,我们在使用原码的时候,我们想要实现一个减法是不行的,我们要转换成加法运算,如果想计算a-a只能计算a+(-a),我们就要找到一个数和(-a)是等效的
接下来我们先介绍一个概念,
模运算
在这里插入图片描述
相信大家可以清楚的看到我们计算机时如何把减法变成加法了吧
我相信细心的小伙伴已经发现了其中的巧合了。我们来看看我们取的补数和补码之间的差别

-14的补数为11110010
-14的补码为11110010

-66的补数为10111110
-66的补码为10111110

这就是补码的由来,所以计算机使用的都是补码之间的运算(补码让减法操作变成加法操作,节省硬件成本,可见那个时候人们是多么聪明)

相信读者看到这里应该完完全全知道了为什么整型数据存储在内存中要使用补码了吧,希望让你有一个更深的理解那我们还有一个问题没有解决啊,我们刚才算出来的补码却没有按照我们所想的方式去存放在内存中,居然是倒着存放的,那我们呢带着个这个疑问来了解大小端知识点吧

💥2.2大小端介绍

一.什么是大小端:

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

在指针那一篇我详细的介绍我们内存是什么样的和地址单元是怎么编号的,并且知道内存地址有高低之分,我们接下来看看图解来更好的理解一下
在这里插入图片描述
我们通过上述图应该充分使用大小端是怎么存储数据了吧,那我们在深入内存看看吧

可以看到我的机器是小端存储模式,如果你的机器是大端存储模式的话可以自己去看看。
二.那为什么会有大小端呢??

为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit。但是在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年系统工程师笔试题:
请简述大端字节序和小端字节序的概念,设计一个小程序来判断当前机器的字节序。(10分)
简述刚才已经说过了,让我们用程序来帮我们去判断我们的机器是大端还是小端,

解题思路:我们要想知道是怎么模式存储的话,那我们就要深入内存,因为大小端是建立在数据在内存中存储的基础上,想到内存,我们就很容易的想到指针,通过指针来访问内存,我们在之前就讲过数据是需要在内存开辟一块内存空间,把数据放进去,所以我们用指针的时候,需要把先得到数据的地址,然后通过解引用来获取里面的数据,通过大小端的存储方式来对比取出来的数字,来看实例
int a=1;
小端 01 00 00 00
大端 00 00 00 01
我们可以发现通过第一个字节的内容可以区分大小端
哪我们怎么只得到第一个字节的内容呢??
这时候就要充分熟练的理解指针类型了,如果直接解引用就会一次访问·四个字节,所以我们通过强制类型转换为char*类型,这样解引用一次就访问一个字节了,话不多说我们来看代码

#include<stdio.h>
int main()
{
int a=1;
 char*p=(char*)&a;
 
 if(*p== 1)
 {
 printf("小端\n");
 }
 else
 {
 printf("大端\n");
 }
 return 0;
}

优化代码
#include<stdio.h>
int main()
{
int a=1;
 if(*(char*)&a== 1)
 {
 printf("小端\n");
 }
 else
 {
 printf("大端\n");
 }
 return 0;
}

大家可以自己来测试一下

我们还可以通过联合体的方式来实现这个代码,具体为什么可以实现,我在讲到联合体知识的时候在细讲,大家可以先看看代码

int check_sys()
{
 union
 {
 int i;
 char c;
 }un;
 un.i = 1;
 return un.c;
}

💤2.3练习

接下来我带大家练习几个题目,充分的在感受一下。

这几个题目要涉及倒截断和整型提升相关的知识,不了解的可以看我的详解操作符这篇博客。

一.

//输出什么?
#include <stdio.h>
int main()
{
    char a= -1;
    -1
    //10000000 00000000 00000000 00000001原码
    //11111111 11111111 11111111 11111110反码
    //11111111 11111111 11111111 11111111补码
    因为a是char类型,只能存放一个字节的数据发生截断所以
    a  11111111
   	因为是以%d的形式打印所以要整型提升,补符号位是1,负数
   	得 11111111 11111111 11111111 11111111
   	在求原码得结果为1

    signed char b=-1;
    -1
    //10000000 00000000 00000000 00000001原码
    //11111111 11111111 11111111 11111110反码
    //11111111 11111111 11111111 11111111补码
    因为a是char类型,只能存放一个字节的数据发生截断所以
    a  11111111
    因为是以%d的形式打印所以要整型提升,是signed有符号类型 补符号位是1,负数
   	得 11111111 11111111 11111111 11111111
   	在求原码得结果为-1
   	
    unsigned char c=-1;
     //10000000 00000000 00000000 00000001原码
    //11111111 11111111 11111111 11111110反码
    //11111111 11111111 11111111 11111111补码
    因为a是char类型,只能存放一个字节的数据发生截断所以
    a  11111111
    因为c是unsigned类型是无符号类型,最高位1变成有效位,所以以%d的的形式打印时需要整型提升补0,正数
    得00000000 00000000 00000000 11111111
    在求原码得结果为255
    printf("a=%d,b=%d,c=%d",a,b,c);-1 -1 255
    return 0;
}

读者可以自己下来测试一下哦,看看结果为什么是这样的

通过这个题目,我相信大家对于整型数据在内存是怎么存储的并且知道了如何取使用它,那我们接下来讲解浮点数在内存是怎么存储的吧

三、浮点型在内存中的存储(float.h)

浮点数的存储和整型的存储时截然不同的,也不存在什么原反补码的形式,我们需要换一种思考方式了,不能在停留在刚才的思维模式了。
常见的浮点数:

3.14159
1E10 表示1*10^10
浮点数家族包括: float、double、long double 类型。

💦3.1一个例子

#include<stdio.h>
int main()
{
 int n = 9;
 float *pFloat = (float *)&n;
 printf("n的值为:%d\n",n);
 printf("*pFloat的值为:%f\n",*pFloat);
 *pFloat = 9.0;
 printf("num的值为:%d\n",n);
 printf("*pFloat的值为:%f\n",*pFloat);
 return 0;
}

我们按照正常思维来想,
第一个打印的是9
第二个打印的是9.0
第三个打印的是9
第四个打印的是9.0
这可以说是按照整型的存储方式来思考问题的,但答案截然不同,这是为什么呢?让我们一起去探讨吧
在这里插入图片描述

🎞️3.2浮点数存储规则

num 和 *pFloat 在内存中明明是同一个数,为什么浮点数和整数的解读结果会差别这么大?
要理解这个结果,一定要搞懂浮点数在计算机内部的表示方法。
根据国际标准IEEE(电气和电子工程协会) 754,任意一个二进制浮点数V可以表示成下面的形式:
(-1)^S * M * 2^E
(-1)^s表示符号位,当s=0,V为正数;当s=1,V为负数。
M表示有效数字,大于等于1,小于2。
2^E表示指数位。

举例来说:
十进制的5.0,写成二进制是 101.0 ,相当于 1.01×2^2 。
那么,按照上面V的格式,可以得出s=0,M=1.01,E=2。
十进制的-5.0,写成二进制是 -101.0 ,相当于 -1.01×2^2 。那么,s=1,M=1.01,E=2。
十进制的5.5,写成二进制是101.1(千万不要写成101.101,位权是一次降低的)相当于1.011×2^2。那么,s=0,M=1.011,E=2.

所以我们只需要知道s M E这三个值,把他们存放在内存中,在需要使用他们的时候,还原这三个数,进行相同的计算不久可以得出我们放进去的数字了吗?

那这三个值具体是以什么方式放在内存当中呢??
IEEE 754规定:
对于32位的浮点数,最高的1位是符号位s,接着的8位是指数E,剩下的23位为有效数字M。
在这里插入图片描述

对于64位的浮点数,最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M。
在这里插入图片描述
这是规定,不需要问为什么s为什么是一位,E为什么是2位这样的问题。

所以刚才那三个数在内存应该是这样的

5.0   1.01×2^2 s=0,M=1.01,E=2
0 0000 0010 101 0000 0000 0000 0000 0000
   0    1   5     0    0    0    0    0
   01  50 00 00
-5.0   -1.01×2^2  s=1,M=1.01,E=2
1 0000 0010 101 0000 0000 0000 0000 0000
  8    1    5    0     0    0   0    0
  81  50   00  00
5.51.011×2^2 s=0,M=1.011,E=2
0 00000010 101 1000 0000 0000 0000 0000
  0   1    5    8     0    0    0    0
  01  58  00  00

在这里插入图片描述
我们看到结果和我们算的不一样说明,这种存储还有漏洞,所以我们还要改进存储方式
IEEE 754对有效数字M和指数E,还有一些特别规定。
前面说过, 1≤M<2 ,也就是说,M可以写成 1.xxxxxx 的形式,其中xxxxxx表示小数部分。
IEEE 754规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的xxxxxx部分。比如保存1.01的时
候,只保存01,等到读取的时候,再把第一位的1加上去。这样做的目的,是节省1位有效数字。以32位浮点数为例,留给M只有23位,将第一位的1舍去以后,等于可以保存24位有效数字

至于放指数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。

指数E从内存中取出还可以再分成三种情况
一.E不全为0或不全为1
这时,浮点数就采用下面的规则表示,即指数E的计算值减去127(或1023),得到真实值,再将有效数字M前加上第一位的1。
比如:
0.5(1/2)的二进制形式为0.1,由于规定正数部分必须为1,即将小数点右移1位,则为1.0*2^(-1),其阶码E为-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的很小的数字。因为2^-126是一个无限接近0的数,所以就直接当成0来看

E全为1
这时,浮点数的指数E等于0-127=128,如果有效数字M全为0,表示±无穷大(正负取决于符号位s);

我们按照这个规则再来计算一下我们刚才那三个数字的存储形式。

5.0   1.01×2^2 s=0,M=1.01,E=2
0 10000001 010 0000 0000 0000 0000 0000
   4   0    a    0    0    0    0    0 
   40  a0  00 00
-5.0   -1.01×2^2  s=1,M=1.01,E=2
1 10000001 010 0000 0000 0000 0000 0000
  c    0    a   0     0    0    0   0
  c0 a0 00 00
5.51.011×2^2 s=0,M=1.011,E=2
0 10000001 011 0000 0000 0000 0000 0000
   4  0   b     0    0    0     0   0
   40  b0 00 00

在这里插入图片描述

我们可以看到数据跟我们计算的是一样的,不过也是倒着存放的,所以浮点数在内存中的存储也是属于小端存储。关于浮点数的规则我们就先讲到这里了。

我们带着这个规则来一起回头看看一开始那个例子为什么会出现这样的问题??

#include<stdio.h>
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("num的值为:%d\n",n);//1091567616
 printf("*pFloat的值为:%f\n",*pFloat);//9.000000
 return 0;
}

在这里插入图片描述
相信已经帮助了大家解决了刚才的疑惑。
特别提醒
我刚才i取的例子都是5.0,5.0这样的数,原因是这样的数字容易精准的得到他的二进制位,如果你举了一个3.14就很难在有限个位中精准的表示他,不信的小伙伴可以试试,如果一个数字,M是32个01组成,那我们在用单精度float类型存储时就会存在精度丢失的问题,这种情况时不可以避免的,那我们就可以采用双精度double类型存储,我们没法保证我们所求的数的M位在我们想要的问题,所以会存在精度丢失的问题,大家练习的时候不要给自己找麻烦

💞四、总结

各位友友们,本章的内容就先到这里了,我们使用计算机操作的就是数据之间的运算,如果不懂数据是怎么在计算机中存储的,那我们怎么能得心应手的学号计算机呢?本片知识量比较大,也是博主花了好长时间整理出来,希望大家可以慢慢消化,更上一层楼,我们下篇再见。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/140432.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

007-Ensp-实验-配置静态路由

实验要求 PC1 可以访问到 PC2 网络结构 实验步骤 1. AR1 G0/0/0 - G0/0/1 配置IP 2. AR2 G0/0/0 - G0/0/1 配置IP 3. PC1 PC2 配置IP/GateWay 4. AR1 配置静态路由表 ip route-static 192.168.1.0 255.255.255.0 192.168.5.2 5. AR2 配置静态路由表 ip route-static 19…

Linux虚拟机克隆后网卡名从eth0变成eth1

文章目录一 系统环境二 问题发现三 解决过程一 系统环境 原本被克隆的主机是 rhel6.9 的操作系统。 二 问题发现 对 rhel6.9 的主机克隆后&#xff0c;发现无法SSH远程连接&#xff0c;从而发现可能是网卡的问题需要解决。 首先检查网卡服务是否启动 发现network服务是正常运…

java在线视频播放系统视频网站影视网站电影电视剧播放网站源码

简介 ssm开发的视频网站。本项目主要包括了视频展示和查询功能&#xff0c;用户中心&#xff0c;积分管理&#xff0c;管理员管理等功能。 演示视频 https://www.bilibili.com/video/BV1tT4y1N7t8/?share_sourcecopy_web&vd_sourceed0f04fbb713154db5cc611225d92156 技…

【408篇】C语言笔记-第二十二章(文件的操作)

文章目录第一节&#xff1a;文件操作原理1. C文件概述2. 文件指针介绍第二节&#xff1a;文件的打开与关闭1. 文件打开与关闭常用函数2. 代码实战第三节&#xff1a;文件的读写1. fread函数与fwrite函数2. fgets函数与fputs函数第四节&#xff1a;文件位置指针偏移1. fseek函数…

2023-01-04 clickhouse-编译、开发、测试

https://bohutang.me/2020/06/05/clickhouse-and-friends-development/ 一次偶然的机会&#xff0c;和ClickHouse团队做了一次线下沟通&#xff0c;Alexey提到ClickHouse的设计哲学: The product must solve actual problemAnd do it better than others 用工程思维解决商业问…

人工智能期末试卷

一、简答题&#xff08;共 24 分&#xff09; 若将人看成一个信息处理系统&#xff0c;1) 人的智能具有哪些特征&#xff1f;2) 举例说明哪一特征是最重要的并 3) 阐述其与实现通用人工智能的关系。(要求&#xff1a;2、3 小问一定用自己的语言作答&#xff01;)&#xff08;8 …

javaweb课程设计-基于SSM框架的疫情数据统计分析系统源码+数据库,可以进行疫情数据录入、疫情数据查询、图表展示

疫情数据统计分析系统 完整代码下载地址&#xff1a;基于SSM框架的疫情数据统计分析系统源码数据库 介绍 疫情数据统计分析系统是一个基于SSM框架的网页端系统&#xff0c;项目中实现的功能如下&#xff1a;用户访问网站可以浏览全国疫情的图表信息&#xff0c;管理员登录后…

P1229 遍历问题

题目描述 我们都很熟悉二叉树的前序、中序、后序遍历&#xff0c;在数据结构中常提出这样的问题&#xff1a;已知一棵二叉树的前序和中序遍历&#xff0c;求它的后序遍历&#xff0c;相应的&#xff0c;已知一棵二叉树的后序遍历和中序遍历序列你也能求出它的前序遍历。然而给定…

人工智能知识图谱研究

1、研究背景及意义 随着互联网技术的发展以及大数据、人工智能等新科技时代的来临&#xff0c;我国高校教育改革、高校人才培养也面临着新的机遇与挑战。一方面&#xff0c;为了实现国家战略、支撑快速发展的新经济&#xff0c;需要高校变革发展培养新型人才&#xff0c;满足社…

Au 效果器详解:自适应降噪

Au菜单&#xff1a;效果/降噪/恢复/自适应降噪Adaptive Noise Reduction自适应降噪 Adaptive Noise Reduction可快速去除变化的宽频噪声&#xff0c;如背景声音、隆隆声、风声等。此效果实时起作用&#xff0c;并可在多轨编辑器中使用。相对于标准降噪效果&#xff0c;自适应降…

cc1-7分析-2

cc2 cc2和cc4呢其实区别也不是很大&#xff0c;最后的rce的方式也都是一样的。区别在哪呢&#xff0c;之前我们说过TemplatesImpl.newTransformer是可以直接进行rce的&#xff0c;cc2就是通过 InvokerTransformer直接去调用TemplatesImpl.newTransformer&#xff0c;不走Insta…

Kubernetes(3)- Serivce详解

第七章 Service详解 本章节主要介绍kubernetes的流量负载组件&#xff1a;Service和Ingress。 Service介绍 ​ 在kubernetes中&#xff0c;pod是应用程序的载体&#xff0c;我们可以通过pod的ip来访问应用程序&#xff0c;但是pod的ip地址不是固定的&#xff0c;这也就意味着…

【数据结构】带头双向循环链表的实现

目录 一、什么是带头双向循环链表 二、带头双向循环链表的实现 1、创建一个动态头结点 2、双向链表初始化 3、打印双向链表 4、双向链表尾插 5、双向链表尾删 6、双向链表头插 7、双向链表头删 8、双向链表查找 9、双向链表在pos的前面进行插入x 10、双向链表删除pos位置的结点…

植物大战僵尸:寻找葵花生产速度

通过CE修改器遍历出控制太阳花吐出阳光的时间变量&#xff0c;太阳花吐出阳光是由一个定时器控制的&#xff0c;首先我们找到第一个太阳花的基址与偏移&#xff0c;然后找出第二个太阳花的动态地址&#xff0c;并通过公式计算得到太阳花结构长度的相对偏移&#xff0c;最后我们…

C++ 大漠插件免注册调用

1&#xff1a; 参考文章&#xff1a; https://blog.csdn.net/chuhe163/article/details/1127455902&#xff1a; 免注册调用代码实现2.1 先建一个空的mfc项目2.2 拷贝dm.dll 到文件项目所在文件夹。2.2.1 拷贝到项目后&#xff0c;右键项目->添加 ->现有项 ->选择dm.d…

四、常用注解

文章目录四、常用注解1、TableName1.1 问题1.2 通过TableName解决问题1.3 通过全局配置解决问题2、TableId2.1 问题2.2 通过TableId解决问题2.3 TableId的value属性2.4 TableId的type属性2.5 雪花算法3、TableField3.1 情况13.2 情况24、TableLogic4.1 逻辑删除4.2 实现逻辑删除…

JavaScript 自执行函数防止冲突全局作用域变量 - 在线客服源码实现弹窗效果JavaScript SDK...

当我在实现在线客服源码弹窗效果JavaScript SDK时&#xff0c;对外公开的SDK代码就是使用的自执行函数的形式。 使用自执行函数来实现 JavaScript SDK 有以下好处&#xff1a; 封装代码&#xff1a;自执行函数可以将你的 JavaScript 代码封装起来&#xff0c;从而避免在全局作用…

文件字节输出流、文件拷贝、资源释放的2种方式

文件字节输出流&#xff1a;写字节数据到文件&#xff1a; API: 注意&#xff1a;close() 包含了 flush() ; 关闭后流就不可以继续使用了 写一个字节出去&#xff1a; 98表示一个字节 写一个字节数组&#xff1a; 注意&#xff1a;写数字和字母可以直接写出去&#xff0c;但…

【二分查找】有界数组中指定下标处的最大值

题目描述 给你三个正整数 n、index 和 maxSum 。你需要构造一个同时满足下述所有条件的数组 nums&#xff08;下标 从 0 开始 计数&#xff09;&#xff1a; nums.length nnums[i] 是 正整数 &#xff0c;其中 0 < i < nabs(nums[i] - nums[i1]) < 1 &#xff0c;其…

leetcode 2244. Minimum Rounds to Complete All Tasks(完成所有task至少要多少轮)

tasks数组里面的数字表示难度的等级&#xff0c;每一轮只能完成2 或者 3个同等级的task, 问至少需要多少轮能完成所有的task, 不能完成的返回-1. 思路&#xff1a; 先来看下什么情况下不能完成。 由于一轮只能完成2 或 3个&#xff0c;那如果该等级的task只有一个呢&#xff…