【C语言】数据在内存中的存储(万字解析)

news2024/11/28 22:35:59

在这里插入图片描述

文章目录

  • 一、大小端字节序和字节序判断
    • 1.案例引入
    • 2.什么是大小端字节序
    • 3.大小端字节序判断
  • 二、整数在内存中的存储以及相关练习
    • 1.整型在内存中的存储
    • 2.练习
      • 练习1:
      • 练习2
      • 练习3
      • 练习4
      • 练习5:
      • 练习6
  • 三、浮点数在内存中的存储
    • 1.案例引入
    • 2.浮点数在内存中的存储规则
    • 3.浮点数存的过程
    • 4.浮点数取的过程
    • 5.案例最后解析

一、大小端字节序和字节序判断

1.案例引入

   在讲解大小端字节序之前,我们先来调试一段代码,来看看一些特别的东西:

#include <stdio.h>

int main()
{
	int a = 0x11223344;
	//整型a存放16进制数
	return 0;
}

   我们来调试一下,打开内存窗口,查看a在内存中的存储形式:
在这里插入图片描述
   调试的时候,我们可以看到在a中的 0x11223344 这个数字是按照字节为单位,倒着存储的,这是为什么呢?这时就要引出我们的大小端字节序了

2.什么是大小端字节序

   其实超过⼀个字节的数据在内存中存储的时候,就有存储顺序的问题,按照不同的存储顺序,我们分为⼤端字节序存储和⼩端字节序存储,下⾯是具体的概念:

  1. 大端存储模式:是指数据的低位字节内容保存在内存的⾼地址处,⽽数据的⾼位字节内容,保存在内存的低地址处
  2. 小端存储模式:是指数据的低位字节内容保存在内存的低地址处,⽽数据的⾼位字节内容,保存在内存的⾼地址处

   是不是有点懵,我们就以上面的那个图来举个例子,来说明什么是低位字节内容,哪里又是低地址:
在这里插入图片描述
   在这里我们可以看出,VS是把高字节数据放在了高地址,把低字节数据放在了低地址处,所以VS中采用了小端字节序的存储方式
   而它看起来倒起来了是因为内存中的地址是由低到高,而一个数字是从高位到低位书写,所以看起来是倒着的

3.大小端字节序判断

   那么我们该怎么判断当前机器采用的字节序呢?这也是百度的一道笔试题,占据了10分,接下来我们就举一个例子来说明
   我们创建一个a变量,让它存放1,来尝试思考一下它分别在大端和小端的存储在内存中的样子,如下:

//大端:
0x 00 00 00 01
//小端:
0x 01 00 00 00

   我们可以发现在存放1时,大端字节序的第一个字节存放的是0,而小端字节序的第一个字节存放的就是1,那我们能否拿到这个整型的第一个字节呢?
   有经验的同学肯定想到了,我们可以创建一个指针变量存放a的地址,然后强制类型转换为字符指针,然后对它解引用,就可以只访问一个字节的内容,然后对解引用的内容进行判断,如果是0那么就是大端字节序,如果是1就说明是小端字节序
   听起来是不是很简单呢?我们来实践一下:

#include <stdio.h>

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

我们来看看运行结果:
在这里插入图片描述
   可以看到运行结果跟我们分析的一样,VS确实采用的是小端字节序存放数据

二、整数在内存中的存储以及相关练习

1.整型在内存中的存储

   在讲解操作符的时候,我们就讲过了下⾯的内容:
   整数的2进制表示方法有三种,即 原码、反码和补码
   有符号的整数,三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,最⾼位的⼀位是被当做符号位,剩余的都是数值位,接下我们来看看它们的特点:

  • 正整数的原、反、补码都相同
  • 负整数的三种表示方法各不相同
  • 原码:直接将数值按照正负数的形式翻译成⼆进制得到的就是原码
  • 反码:将原码的符号位不变,其他位依次按位取反就可以得到反码
  • 补码:反码+1就得到补码

   我们之前也讲过,对于整型来说,在内存中其实存放的是补码,为什么呢?
   原因在于,使⽤补码,可以将符号位和数值域统⼀处理;同时,加法和减法也可以统⼀处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路
   正整数的原反补码相同,这里就不再举例说明了,我们再复习一下负整数转为补码的过程,就以-5举例:

原码:10000000 00000000 00000000 00000101

   反码:除了符号位,对原码其它位全部取反

11111111 11111111 11111111 11111010

   补码:反码+1,是计算机内部存储整型的形式

11111111 11111111 11111111 11111011

2.练习

练习1:

   试着计算以下代码的运行结果:

#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;
}

   首先就是字符型的a被赋值为整型-1,所以我们首先要求到-1的补码,然后对其进行截断,截断为1个字节,就是字符a真正的值,而截断的知识在操作符中已经讲过,忘记了的可以自行翻阅,我们现在开始处理a:

-1
原码:10000000 00000000 00000000 00000001
反码:11111111 11111111 11111111 11111110
补码:11111111 11111111 11111111 11111111

   此时由于a是字符型,所以要截断前三个字节,留下最后一个字节,所以a最后就是这个:

11111111

   由于char默认就是signed char,也就是有符号的char,所以这样最高位的1是符号位,此时a存放的是11111111
   然后我们来看b,b是一个有符号char,跟我们上面的a一模一样,所以它存放的也是11111111
   最后我们来看c,c是一个无符号char,却被赋值了有符号的-1,该怎么计算呢?这个就要看我们的赋值运算符的结合性了,在外面操作符那里也讲过,它是从右向左计算的,如图:
在这里插入图片描述
   也就是会先计算赋值运算符右边的东西,然后再将结果赋值给左边,所以在这里我们还是要先看右边,不看左边的无符号char,我们通过上面的计算,知道了整型-1的补码为:

11111111 11111111 11111111 11111111

   这个时候我们要赋值给无符号char,首先截断为:

11111111

   计算到这里后,我们知道了c里面也是11111111,但是由于赋值给了无符号char,所以这里所有位置都是数值位,不含符号位

   但是问题又来了,最后打印时居然用的%d,%d表示打印有符号整型,%u是无符号整型,这里统一用的%d,以有符号整型打印abc,但是abc是字符型啊,怎么办?当然是要进行整形提升了,提升到整形一样的4个字节
   整形提升的规则我们也讲过,就是有符号数高位补符号位,直到4个字节,无符号数就高位全部补0,凑齐4个字节
   现在我们就对a进行整型提升,按符号位补齐4个字节:

11111111 11111111 11111111 11111111

   这里得到的是补码,转换为原码为:

10000000 00000000 00000000 00000001

   这就是得到的最后的答案,以%d的形式打印a结果为-1,由于b和a一样,所以打印的结果也是-1
   最后来看c,先对c进行整型提升,由于c是无符号char,所以高位补0,补齐4个字节,如下:

00000000 00000000 00000000 11111111

   经过整型提升后我们可以看到它变成了一个符号位为0的正整数,由于正数的原反补码相同,所以这就是它的原码,计算出来为正的255
   通过我们的不懈努力终于将它分析清楚了,a和b打印出来是-1,而c打印出来是255,接下来我们来看看代码运行的结果:
在这里插入图片描述

练习2

   试着计算以下代码的运行结果:

#include <stdio.h>

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

   经过练习1的练习,我们现在应该已经会做一点类似的题了,我们再拿相似的练习2来练练手
   首先我们来看a,要计算出-128的补码,这里直接给出转换过程,最好自己计算一遍,不要直接看答案:

原码:10000000 00000000 00000000 10000000 
反码:11111111 11111111 11111111 01111111
补码:11111111 11111111 11111111 10000000

   随后进行截断,变成:

10000000

   然后我们来看b,128是个正数,所以原码就是补码,如下:

补码:00000000 00000000 00000000 10000000

   经过截断后变成:

10000000

   可以发现a和b存放的都是10000000,由于要以%u的形式打印,也就是无符号整型的方式打印,所以首先要进行整型提升,如下:

11111111 11111111 11111111 10000000

   由于以无符号整型的形式打印,所以这里的所有位都表示数值位,有点大,所以我们可以将其复制进电脑的计算器来计算,如下:
在这里插入图片描述
   由于a和b经过截断和整型提升都是一样的,所以答案应该也是一样,接下来我们就来运行一下程序,看看和我们计算器算出的答案是否一致,如下:
在这里插入图片描述
   可以看到完全一致,所以我们的分析是正确的

练习3

   试着计算以下代码的运行结果:

#include <stdio.h>
#include <string.h>

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

   这道题有一些难度,要了解一些关于char的知识,char默认为有符号char,它的取值范围为 -128 ~ 127 ,其中-128是人为规定的,因为在计算机中有这么两个特殊的数:

00000000
10000000

   按照原本的计算方式计算,就会发现前面是0,后面那个是-0,但是由于并不存在-0,所以人为规定为了-128
   随后我们来做这个题,这个题的关键在于那个strlen(a),我们知道strlen计算字符串长度时的结束条件是碰到\0时,统计\0前的字符的个数
   而\0的值实际是0,所以这道题的关键就在于经历多少个字符之后,数组中出现了0,算出0之前出现的字符的个数
   我们现在就开始分析,当i=0时,a[0]就是-1,当i=1,a[1]就是-2,依次类推,我们来找一个分界点,没错就是-129,-1到-128一共128个数都是char能存放的,而-129就超出了边界
   接下来我们来求-129的补码:

原码:10000000 00000000 00000000 10000001
反码:11111111 11111111 11111111 01111110
补码:11111111 11111111 11111111 01111111

   经过截断后变成了:

01111111

   是不是非常神奇,居然直接变成了127,也就是我们可以记住,在char中-128再-1就变成了127,
   然后我们就又这样推下去,从127慢慢开始减1,如:126,125,124······,那么这段数据的关键在哪里呢?没错,就在0这里,经过-1操作,最后会变成0
而strlen碰到这个0就结束计算了,那我们来看看这个0之前有多少个数,首先是从-1到-128,一共128个数,然后就是127到1,一共127个数,注意不会算上0,所以一共就是128+127=255个数
   我们来看看运行结果,看看我们分析的是否正确:
在这里插入图片描述
   可以看到跟我们预想的完全正确
   在解决这道题之后,我们可以来总结一下char的规律,刚刚我们是每个数慢慢减1,产生了轮回,那如果我们从0开始一直加1会产生什么循环呢?如图:
在这里插入图片描述
   可以看到,只要从1开始,一直加1,就会按照上图的形式,用顺时针的方式构成轮回,而我们上面做的那个题就是从-1开始,一直减1,就会以逆时针的方式构成轮回

练习4

   试着计算以下代码的运行结果:

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

   这里会打印多少个hello world呢?是不是256个呢?很明显不会这么简单,我们来分析一下,unsigned char是无符号char它的范围是0~255
   前面都没有问题,问题在于,当i=255时,也符合条件,会打印一次hello world,然后i+1后变成了256,但是256超出了unsigned char的范围,所以我们要来计算一下256如果放入unsigned char是多少:

原码:00000000 00000000 00000001 00000000

   经过截断后:

00000000

   我们发现居然将256放入unsigned char后,变成了0,此时i就重新变成了0,又开始循环,到下一个256又变成0,又循环,周而复始,造成了死循环
   我们来看看运行结果:
在这里插入图片描述
   果然是死循环的打印hello world

练习5:

   试着计算以下代码的运行结果:

#include <stdio.h>

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

   这道题和上一道题很相似,它的关键在于i=0时,进入循环打印了i,然后减1,变成了-1,但是超过了无符号char的范围,所以要重新计算:

原码:10000000 00000000 00000000 00000001
反码:11111111 11111111 11111111 11111110
补码:11111111 11111111 11111111 11111111

   经过截断后:

11111111

   由于i是无符号char,没有符号位,全部是数值位,所以就变成了255,所以我们知道了,当i到达-1时会变成255,然后又开始循环,直到又到达-1,又变成255继续循环,构成了死循环,我们来看看运行结果:
在这里插入图片描述
   数字这么大的原因是采用了%u的形式进行打印,会有整型提升,可以自己尝试整形提升后是否是这些值
   经过上面两个题的练习,我们基本应该了解了一个东西,就是无符号整型的范围是0~255,如果使用循环时超出这个范围,可能就会经过一直截断,导致造成死循环,有符号整型也是如此,不能超出范围,否则会一直截断,一直循环

练习6

   我们来看关于整型存储的最后一个练习:

#include <stdio.h>
//X86环境 ⼩端字节序
int main()
{
 int a[4] = { 1, 2, 3, 4 };
 int *ptr1 = (int *)(&a + 1);
 int *ptr2 = (int *)((int)a + 1);
 printf("%x,%x", ptr1[-1], *ptr2);
 return 0;
}

   这道题有点难度,它结合了我们指针的知识,但是我们已经刷了很多指针题了,这道题也是出自我们练过的某题,如果还没有刷过指针的题,看以参照我的博客:【C语言】手把手带你拿捏指针(完)(指针笔试、面试题解析)
   这道题要求的是x86环境下,并且是小端字节序,我们的VS都符合这个要求,这个题最好画图求解,如下图:
在这里插入图片描述
   把图画出来了这道题就比较简单了,首先这里是用%x方式打印,也就是打印16进制,ptr1[-1]相当于就是*(ptr1 - 1),这里ptr1是整型指针,所以它会指向最后一个整型,如图:
在这里插入图片描述
   所以第一个ptr[-1]打印出来就是4,我们接着来看第二个,这里是对ptr2解引用,ptr2解引用后访问4个字节,也就是上图的00 00 00 02,由于是小端字节序,所以第二个里面存放的是02 00 00 00,由于这本身就是16进制,所以打印出来就是2000000
   我们来看看最后的运行结果:
在这里插入图片描述
   与我们分析的别无二致

三、浮点数在内存中的存储

1.案例引入

   常见的浮点数:3.14159、1E10等,浮点数家族包括: float、double、long double 类型。浮点数表⽰的范围: float.h 中定义
   我们用一个案例来分析引入一下:

#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;
}

(1)首先第一个printf是正常打印9,就不再说了

(2)然后我们来看第二个printf,我们就要来看一下pFloat是什么,pFloat是int的地址强制类型转换成float的地址,所以现在*pFloat就是以浮点型float的角度来解引用n,但是我们不知道浮点型是怎么存储的,就不知道结果,就暂时放在这里,等我们后面讲完再来计算

(3)接着我们来看第三个printf,上面通过对pFloat解引用,以浮点型的角度来把n改成了9.0,所以这里我们要探究的是通过浮点型角度更改整型是什么样子的,后面我们讲到了再回来计算

(4)最后来看最后一个printf,上面通过对pFloat解引用,以浮点型的角度来把n改成了9.0,此时站在浮点型的角度对它进行打印,必然就能打印出来9.0的效果,这个稍加分析就可以得到

   所以经过我们的分析,发现了第二个和第三个printf的结果还是未知的,接下来我们就来学习浮点数在内存中的存储,然后再回来解决这两个问题

2.浮点数在内存中的存储规则

   浮点数在内存中的存储有一个公式,这个公式类似于我们平常学的10进制的科学计数法,我们举一个10进制的科学计数法,如下:

19971400000000=1.99714×10^13
//其中的小数的范围是大于等于1,小于10

   只是我们马上学习的公式是2进制版的,接下来我们会采用类比的方法来学习,这样比较好理解,现在就让我们正式开始学习:
   根据国际标准IEEE(电⽓和电⼦⼯程协会) 754,任意⼀个⼆进制浮点数V可以表示成下面的形式:
在这里插入图片描述
   我们一个一个来分析浮点数V在存储时,公式中的三个参数S、M、E,以及底数2的含义

  1. S:公式中的S用于控制这个浮点数的正负性,当S=0时,浮点数V为正数,当S=1时,浮点数V为负数
  2. M:公式中M是一个大于等于1,小于2的有效数字,它类似于10进制科学计数法中的小数,如:19971400000000=1.99714×10^13中的1.99714这个小数,而十进制中这个小数范围是大于等于1,小于10,我们二进制就是大于等于1,小于2
  3. E:公式中的E表示指数,类似于10进制科学计数法中的那个指数,如:19971400000000=1.99714×10^13中的次方13,而十进制中的底数是10,二进制中的底数是2

   现在我们举一个例子来更好的说明,比如浮点型数字5.0,将其转换为2进制为101.0
   按照上面我们讲的公式套的话就是:
在这里插入图片描述
   其中我们的S为0,表示该浮点数是一个正数,M为1.01,是用来表示该浮点数的有效数字,最后就是E为2,表示我们的指数,也就是我们小数点移动了几位,在这里就是小数点移动了2位,通过乘以2的2次方可以还原回去
   然后我们再次和十进制的科学计数法作类比:

19971400000000=1.99714×10^13

   其中的13就是指数,用来表示小数点移动了多少位,这里就是小数点移动了13位,所以可以通过乘以10的13次方就可以让那个小数还原
通过类比是不是就感觉好理解多了呢!
   接下来我们继续学习,在存储浮点数时,SME这三个重要参数分别占的空间大小:
   IEEE 754规定:

  • 对于float类型的32位的浮点数,最⾼的1位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数字M,如图:
    在这里插入图片描述

  • 对于double类型的64位的浮点数,最⾼的1位存储符号位S,接着的11位存储指数E,剩下的52位存储有效数字M,如图:
    在这里插入图片描述

3.浮点数存的过程

(1)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位有效数字

(2)⾄于指数E,情况就⽐较复杂,⾸先,E为⼀个⽆符号整数,这意味着,如果E为8位,它的取值范围为0 ~ 255;如果E为11位,它的取值范围为0 ~ 2047
   但是,我们知道,科学计数法中的E是可以出现负数的,例如2的-1次方,这里的E就是-1,所以IEEE 754规定,存⼊内存时E的真实值必须再加上⼀个中间数:
   对于8位的E,取值范围为0 ~ 255,这个中间数是127;对于11位的E,取值范围为0 ~ 2047,这个中间数是1023
   ⽐如,2 ^ 10的E是10,所以保存成32位浮点数时,必须保存成10+127=137,即10001001,而2 ^ -1的E是-1,所以保存为32为浮点数时,必须保存为-1+127=126,即01111110

4.浮点数取的过程

   指数E从内存中取出还可以再分成三种情况:
(1)加上中间值后E不全为0或不全为1:
   这时,浮点数就采⽤下⾯的规则表⽰,即指数E的计算值减去127(或1023)的中间值,得到真实值,再将有效数字M前加上第⼀位的1
   ⽐如:0.5 的⼆进制形式为0.1,由于规定正数部分必须为1,即将⼩数点右移1位,则为1.0*2^(-1),其阶码为-1+127(中间值)=126,表示为01111110
   而尾数1.0去掉整数部分为0,补⻬0到23位:00000000000000000000000,则其⼆进制表示形式为:

 0 01111110 00000000000000000000000
 S     E           M

   此时的E不为全0或全1,是126,所以在取出时就要重新给E减去中间值127,然后把M去掉的整数1补回来
(2)加上中间值后E全为0
   我们知道32位的中间值是127,E加上了127后还是全0,说明此时原本的E,也就是真实值就是-127,想象一下2^(-127),是一个非常非常小的数,无限接近于0了,然后再乘以我们的M也无济于事
   所以此时有效数字M不再加上第⼀位的1,⽽是还原为0.xxxxxx的⼩数。这样做是为了表⽰±0,以及接近于0的很⼩的数字

(3)加上中间值后E全为1
   我们知道32位的中间值是127,E加上了127后是全1,也就是255,它原本的E,也就是真实值就是128,说明这是一个无限接近于无穷大的情况
   所以如果有效数字M全为0,表⽰±⽆穷⼤(正负取决于符号位s)

5.案例最后解析

   最后我们知道了浮点数的存储,我们再次把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;
}

   我们来看第二个printf,现在我们尝试着以浮点型的角度来解析n,首先我们写出n的补码,n是正数,原码就是补码,如下:

00000000 00000000 00000000 00001001

   然后以浮点型的角度来重新把它拆解一下,如下:

0 00000000 00000000000000000001001
S    E               M

   我们上面讲过,如果E为全0,说明这个数非常非常的小,所以在还原时,就不会还原M前面的整数1,现在我们有了SME,带入我们的公式试试看这个数是多少:

(-1)^0 * 0.00000000000000000001001 * 2^(-127)

   我们可以看到这里的M已经非常小了,往后数6位小数点都看不到一个1,何况后面还要乘以2的-127次方,乘下来会非常非常小,在碰到1前会有100多个0,小数点后100多个0,可以想象出来有多小,无限接近于0,所以在打印时,就会显示0

   我们来看第三个printf,首先我们就要算出上面以浮点型角度往n存放了一个9.0,我们来看看9.0存储到内存是什么样子的,主要是求SME,首先将9.0转为二进制:

1001

   然后写出我们的SME

S:0
M:1.001
E:3

   我们求出来E是3,加上中间值127就是130,所以我们写出E的八位二进制应该为:

10000010

   所以最后浮点数9.0在内存中存储的二进制序列为(注意存放顺序为SEM):

0 10000010 00100000000000000000000
S    E             M

   现在我们要以整型的角度来看待这段二进制,首先我们对它进行拆分:

01000001 00010000 00000000 00000000

   可以看出来这个数是一个正数,并且非常非常大,我们可以拿进计算器计算一下:
在这里插入图片描述
   可以想到我们第三个printf打印出来的值应该就是这样
   最后我们来总结一下:第一个printf打印9,第二个printf打印0.000000,第三个printf打印1091567616,最后一个printf打印9.000000,我们来看运行结果:
在这里插入图片描述
   可以看到结果和我们算出来的一模一样,是不是非常有成就感呢?
   今天的数据在内存中的存储到此结束了,稍微有点难,可以多看多问,在评论区欢迎提问,或者私信我,一定倾囊相授
   拜拜~~

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

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

相关文章

uniapp+Android面向网络学习的时间管理工具软件 微信小程序

目录 项目介绍支持以下技术栈&#xff1a;具体实现截图HBuilderXuniappmysql数据库与主流编程语言java类核心代码部分展示登录的业务流程的顺序是&#xff1a;数据库设计性能分析操作可行性技术可行性系统安全性数据完整性软件测试详细视频演示源码获取方式 项目介绍 用户功能…

KVM虚拟化技术介绍

文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 虚拟化技术是云计算的基础&#xff0c;什么是虚拟化&#xff1f;虚拟化技术的本质是什么&#xff1f;主流的虚拟化技术有哪些&#xff1f;本章将为您揭晓 一.虚拟化概述 虚拟化是一种将计…

【有啥问啥】领域自适应(Domain Adaptation, DA)详解

领域自适应&#xff08;Domain Adaptation, DA&#xff09;详解 引言 在机器学习和深度学习的广泛应用中&#xff0c;一个核心挑战在于模型往往在一个特定数据集&#xff08;源领域&#xff09;上训练后&#xff0c;难以直接应用于另一个不同但相关的数据集&#xff08;目标领…

通信工程学习:什么是ICMP因特网控制报文协议

ICMP&#xff1a;因特网控制报文协议 ICMP&#xff08;Internet Control Message Protocol&#xff0c;因特网控制报文协议&#xff09;是TCP/IP协议簇中的一个重要子协议&#xff0c;主要用于在IP主机和路由器之间传递控制消息。以下是关于ICMP协议的详细解释&#xff1a; 一…

Pikachu-Unsafe FileUpload-客户端check

上传图片&#xff0c;点击查看页面的源码&#xff0c; 可以看到页面的文件名校验是放在前端的&#xff1b;而且也没有发起网络请求&#xff1b; 所以&#xff0c;可以通过直接修改前端代码&#xff0c;删除 checkFileExt(this.value) 这部分&#xff1b; 又或者先把文件名改成…

九、2 USART串口外设

1、STM32内部的USART外设的介绍 &#xff08;1&#xff09; STM32的USART的同步模式只是多了个时钟输出&#xff0c;只支持时钟输出&#xff0c;不支持时钟输入。该同步模式更多是为了兼容别的协议或者特殊用途而设计的&#xff0c;并不支持两个USART之间进行同步通信&#xf…

剖解最小栈

最小栈 思路&#xff1a; 1. 首先实例化两个栈&#xff0c;分别是stack用于存放数据&#xff0c;minstack用于存放最小值 2. 将第一个元素压入两个栈中&#xff0c;判断此时若minStack栈中为空&#xff0c;则表示压入的为第一个数据 if ( minStack.empty () ) { minStack.pus…

MySQL 查询优化器

文章目录 控制查询计划optimizer_prune_leveloptimizer_search_depth 优化器参数优化器提示索引提示成本模型server_costcost_name engine_cost 控制查询计划 https://dev.mysql.com/doc/refman/8.4/en/controlling-query-plan-evaluation.html 在执行SQL前会根据优化器选择执…

Leetcode 第 140 场双周赛题解

Leetcode 第 140 场双周赛题解 Leetcode 第 140 场双周赛题解题目1&#xff1a;3300. 替换为数位和以后的最小元素思路代码复杂度分析 题目2&#xff1a;3301. 高度互不相同的最大塔高和思路代码复杂度分析 题目3&#xff1a;3302. 字典序最小的合法序列思路代码复杂度分析 题目…

入手一个小扒菜fqrr#com

fqrr#com 既带q又带r是很多人不喜的类型&#xff0c; 父亲 夫妻 番茄 分期 人人 日日 好无聊的米呀&#xff0c;竟然组合不出来意思 这个不是购买的&#xff0c;别人说他1150元购买的&#xff0c;算是半抵给我的吧 其实我也不喜欢&#xff0c;我4声母.com 已经够多了&am…

【教程】文字转语音的3个方法,文字转语音使用攻略

文字转语音的需求还是蛮多的&#xff0c;很多用户在视频剪辑中会遇到。不想用本人的声音&#xff0c;那么视频中的旁白就只能通过文字转语音软件实现了。 想要将文字转为语音那还是蛮好解决的&#xff0c;如果你还在找方法&#xff0c;那么以下内容可以了解下。本文整理了三种简…

2c 操作符详解

1. 操作符分类&#xff1a; 算术操作符 移位操作符 位操作符 赋值操作符 单目操作符 关系操作符 逻辑操作符 条件操作符 逗号表达式 下标引用、函数调用和结构成员 2. 算术操作符 - * / % 1除了 % 操作符之外&#xff0c;其他的几个操作符可以作用于整数和浮点数。对于 / 操作…

NVIDIA NVLink-C2C

NVIDIA NVLink-C2C 文章目录 前言一、介绍1. 用于定制芯片集成的超快芯片互连技术2. 构建半定制芯片设计3. 使用 NVLink-C2C 技术的产品 二、NVLink-C2C 技术优势1. 高带宽2. 低延迟3. 低功率和高密度4. 行业标准协议 前言 将 NVLink 扩展至芯片级集成 一、介绍 1. 用于定制芯…

Candance仿真二阶米勒补偿OTA

1.OTA电路搭建目标——25Mhz GBW&#xff0c;65dB的增益 2.电路参照 3.candance电路搭建 实现步骤&#xff1a;应该是从下面这个公式开始推导 然后那个CL就是两边的那个CCa或CCb的大小 算出来就是gm75us

MongoDB-aggregate流式计算:带条件的关联查询使用案例分析

在数据库的查询中&#xff0c;是一定会遇到表关联查询的。当两张大表关联时&#xff0c;时常会遇到性能和资源问题。这篇文章就是用一个例子来分享MongoDB带条件的关联查询发挥的作用。 假设工作环境中有两张MongoDB集合&#xff1a;SC_DATA&#xff08;学生基本信息集合&…

基于微信小程序的旅游拼团系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

Colorize: 0 variables Colorize is not activated for this file. VsCode

问题情况 解决步骤 1.找到setting.json文件 2.输入以下代码&#xff0c;保存setting.json文件 "colorize.languages": ["css", "javascript", "sass", "less", "postcss", "stylus", "xml"…

基于SpringBoot+Vue+MySQL的中医院问诊系统

系统展示 用户前台界面 管理员后台界面 医生后台界面 系统背景 随着信息技术的迅猛发展和医疗服务需求的不断增加&#xff0c;传统的中医院问诊流程已经无法满足患者和医院的需求。纸质病历不仅占用大量存储空间&#xff0c;而且容易丢失和损坏&#xff0c;同时难以实现信息的快…

螺蛳壳里做道场:老破机搭建的私人数据中心---Centos下Docker学习04(环境准备)

4 创建docker容器 4.1创建网络 [rootlocalhost wutool]# docker network create -d macvlan --subnet192.168.137.0/24 --gateway192.168.137.2 --ip-range192.168.137.0/24 -o parentens33 nat 52af11381bfd655d175e4168265b2a507793e8fe48f119db846949ffd4dd27de [rootlocal…

【每天学个新注解】Day 15 Lombok注解简解(十四)—@UtilityClass、@Helper

UtilityClass 生成工具类的注解 将一个类通过注解变成一个工具类&#xff0c;并没有什么用&#xff0c;本来代码中的工具类数量就极为有限&#xff0c;并不能达到减少重复代码的目的 1、如何使用 加在需要委托将其变为工具类的普通类上。 2、代码示例 例&#xff1a; Uti…