首页 > 系统相关 >数据在内存中的存储

数据在内存中的存储

时间:2024-03-16 20:29:24浏览次数:21  
标签:11111111 存储 字节 符号 int 浮点数 char 内存 数据

在这里插入图片描述

目录

1. 整数在内存中的存储

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

正整数的原、反、补码都相同。
负整数的三种表⽰⽅法各不相同。

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

对于整形来说:数据存放内存中其实存放的是二进制的补码。为什么呢?
在计算机系统中,数值⼀律⽤补码来表⽰和存储。
原因在于,使⽤补码,可以将符号位和数值域统⼀处理;同时,加法和减法也可以统⼀处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是
相同的,不需要额外的硬件电路。

2. ⼤⼩端字节序和字节序判断

当我们了解了整数在内存中存储后,我们调试看⼀个细节:

#include <stdio.h>
int main()
{
	int a = 0x11223344;

	return 0;
}

调试的时候,我们可以看到在a中的 0x11223344 这个数字是按照字节为单位,倒着存储的。这是为
什么呢?
在这里插入图片描述
注:
1、整数在内存中 存储的是二进制的补码
2、在调试窗口中观察内存的时候,为了方便展示,显示的是16进制的值
3、存储的顺序是倒过来的

2.1 什么是⼤⼩端?

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

拿上面的0x11223344举例:

在讲指针的时候,我们就说过,每个内存单元的⼤⼩取1个字节。
存储一个整型数据我们需要用到4个字节,那么,这4个字节存储的时候就需要拆成4个字节来存储,每个字节占一个内存单元,就出现了顺序的问题。
在此处,小编列出了4种,其实这4种都可以(如何存进去就如何拿出来,结果正确便可),但是由于右边两种的存放方式比较别扭,所以就去除掉了右边两种乱的排列方式,留下正着放与倒着放的两种方式,而它们分别有个名字----大端字节序存储、小端字节序存储

在这里插入图片描述

⼤端(字节序存储)模式:
是指数据的低位字节内容保存在内存的⾼地址处,⽽数据的⾼位字节内容,保存在内存的低地址处。
⼩端(字节序存储)模式:
是指数据的低位字节内容保存在内存的低地址处,⽽数据的⾼位字节内容,保存在内存的⾼地址处。

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处理器还可以由硬件来选择是⼤端模式还是⼩端模式。

2.3 练习

2.3.1 练习1

请简述⼤端字节序和⼩端字节序的概念,设计⼀个⼩程序来判断当前机器的字节序。

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



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

此处强制类型是做不到的
在这里插入图片描述

unsigned int a= 0x1234;
unsigned char b = *(unsigned char *)&a;

在32位大端模式处理器上变量b等于什么?

在这里插入图片描述
将&a强转为unsigned char*类型后,访问一个低地址字节,得到的就是0,所以变量b等于0x00

2.3.2 练习2

在这里插入图片描述
在这里插入图片描述

#include <stdio.h>
int main()
{
	//char到底是有符号的char还是无符号的char,取决于编译器,在VS中,是signed char

	//-1
	//10000000 00000000 00000000 00000001 --- 原码
	//11111111 11111111 11111111 11111110 --- 反码
	//11111111 11111111 11111111 11111111 --- 补码
	//由于a是char类型,占1字节,即8个bit位,所以发生了截断

	char a = -1;
	//11111111 --- a(有符号数)
	//通过%d打印的是有符号整数,而a、b、b都是个字符,需要进行整型提升
	
	//1、有符号整数提升是按照变量的数据类型的符号位来提升的,直接补符号位
	//2、⽆符号整数提升,⾼位补0
	
	//11111111 11111111 11111111 11111111 
	signed char b = -1;//(有符号数)
	//11111111 --- b
	//进行整型提升
	//11111111 11111111 11111111 11111111 
	unsigned char c = -1;//(无符号苏)
	//11111111 --- c
	//由于c是unsigned char类型,所以高位补0
	//00000000 00000000 00000000 11111111

	//提升完后,由于%d打印,认为内存中的是有符号整数,在通过%d打印时需转换为原码打印,
	//a、b都需计算为原码才能打印,而c符号位是0,代表正数,正数的原反补码相同,不需转换
	printf("a=%d,b=%d,c=%d", a, b, c);
	return 0;
}

运行结果如下:
在这里插入图片描述

2.3.3 练习3

#include <stdio.h>
int main()
{
	//10000000 00000000 00000000 100000000
	//11111111 11111111 11111111 011111111
	//11111111 11111111 11111111 100000000
	//a是char类型,发生截断
	//10000000 -- a
	//整型提升
	//11111111 11111111 11111111 10000000
	char a = -128;
	printf("%u\n", a);
	//%u的形式打印,是认为a中存放的是无符号数
	return 0;
}
#include <stdio.h>
int main()
{
	char a = 128;
	//128
	//00000000 00000000 00000000 10000000 -- 原码(正数原反补码相同)
	//截断
	//10000000 -- a 代表
	//进行整型提升,char类型,所以高位代表符号位
	//11111111 11111111 11111111 10000000
	//以%u形式打印,认为内存中的是补码,且其是无符号数(即正数),而正数原反补码相同
	printf("%u\n", a);
	return 0;
}

3个练习小总结

总的来说,将某个值赋予某个低于整型的类型的变量时,会将其先转换为补码,再通过类型进行截断,拿上面几个代码举例,上面各个代码中将-1、-128、128均赋予char类型变量或unsigned char类型变量或signed char类型变量(char是signed char还是unsigned char,取决于编译器,小编所用的是VS,编译器将char默认为signed char),会将-1,-128,128均转换为补码(正整数的原、反、补码都相同;负整数的三种表⽰⽅法各不相同。所以正数不需进行转换)

11111111 11111111 11111111 11111111 --- (-1的补码)
11111111 11111111 11111111 10000000 --- (-128的补码)
00000000 00000000 00000000 10000000 --- (128的补码)

进行截断(根据类型截取):由于char类型只占一个字节,即8个bit位,所以截取8个比特位的数值。

11111111 --- (-1截断后的结果)
10000000 --- (-128截断后的结果)
10000000 --- (128截断后的结果)

截取完成后,由于%d打印的是十进制整数、%u都是打印的是无符号整数(unsigned int),所以需要进行整型提升,整型提升在操作符(2)中有讲解过,这里列出整型提升的规则:
1、有符号整数提升是按照变量的数据类型的符号位来提升的,直接补符号位
2、⽆符号整数提升,⾼位补0
这里拿VS编译器为例:

在上面代码中,-1被分别赋予了char、signed char、unsigned char三种类型的变量,-128被赋予了char类型
的变量,128被赋予了char类型的变量。
在VS编译器中,char默认为signed char,所以,char与signed char都认为其变量为有符号数,提升是按照
其变量数据类型的符号位来提升的,而unsigned char代表的是无符号数,高位直接补0

因此,对于变量的值是-1且类型是char与signed char的变量,整型提升结果是:
11111111 11111111 11111111 11111111 --- 补码

通过%d形式打印,认为是有符号整数,打印出来需要转换为原码;转换规则:符号位不变,数值位取反加一,
结果如下:
10000000 00000000 00000000 00000001 --- -1的原码
所以,被赋予-1的char与signed char类型的变量通过%d打印的结果为-1

对于被赋予了-1的unsigned char类型的变量,整型提升的结果是:
00000000 00000000 00000000 11111111 --- 255的补码(正数的原反补码相同)

对于被赋予了-128的char类型的变量,由于在VS编译器中char默认为signed char,所以认为被赋予-128的变
量是有符号数,按符号位来提升,整形提升结果如下:
11111111 11111111 11111111 10000000
通过%u形式打印,打印的是无符号整数,认为变量内存中的是补码,且其是无符号数(即正数),而正数原反
补码相同
所以直接将11111111 11111111 11111111 10000000转换为十进制形式输出,结果为4294967168

对于被赋予了128的char类型的变量,由于在VS编译器中char默认为signed char,所以认为被赋予128的变
量是有符号数,按符号位来提升,整形提升结果如下:
11111111 11111111 11111111 10000000
通过%u形式打印,打印的是无符号整数,认为变量内存中的是补码,且其是无符号数(即正数且高位不再是符号
位),而正数原反补码相同
所以直接将11111111 11111111 11111111 10000000转换为十进制形式输出,结果为4294967168

即在通过%d或%u打印前,整型提升结果仍然存放在内存中,若为%d形式打印,则将高位当作符号位来打印,
为%u形式打印,则全为数值位,不存在符号位

换句话说,本来上面的unsigned c=-1,本来认为c是无符号数,但耐不住有人想用%d打印,吃饱了撑的
所以,小编建议以后大家用的时候,有符号数就用有符号的占位符打印,无符号的用无符号的占位符打印

2.3.4 练习4

#include <stdio.h>
int main()
{
	char a[1000];
	int i;
	for (i = 0; i < 1000; i++)
	{
		a[i] = -1 - i;
	}
	//-1 -2 -3 -4 -5 .... -127 -128 -129 -130
	printf("%d", strlen(a));//求得是字符串的长度,统计的是\0(ASCII码值是0)之前的字符个数
	return 0;
} 

上述代码中,char类型的最小值是-128,如-129、-130等是不属于该范围的,那它能存放-129、-130么----应该是不可以的,那么,-129、130存进去是什么呢?
在这里插入图片描述

在这里插入图片描述

由上图我们可以知道,-128之后会到127,继续循环下去,
-1 -2 -3 -4 -5 -6 ... -127 -128 127 126 125 ... 4 3 2 1 0 -1 -2 ...
直到i=1000停止,而上述又讲过'\0'的ASCII码值为0,在0之前有255个数,
所以strlen(a)结果为255
#include<stdio.h>
int main()
{
  unsigned char a = 200;
  unsigned char b = 100;
  unsigned char c = 0;
  c = a + b;
  printf(“%d %d”, a+b,c);
  return 0;
}

说明:printf在传入参数的时候如果是整形会默认传入四字节,所以a+b的结果是用一个四字节的整数接收的,不会越界。而c已经在c = a + b这一步中丢弃了最高位的1,所以只能是300-256得到的44了。

※由于printf是可变参数的函数,所以后面参数的类型是未知的,所以甭管你传入的是什么类型,printf只会根据类型的不同将用两种不同的长度存储。其中8字节的只有long long、float和double(注意float会处理成double再传入),其他类型都是4字节。所以虽然a + b的类型是char,实际接收时还是用一个四字节整数接收的。另外,读取时,%lld、%llx等整型方式和%f、%lf等浮点型方式读8字节,其他读4字节。

2.3.5 练习5

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

上述代码运行会陷入死循环,为什么呢?
通过 2.3.4 练习4中的例图我们可以推出,其实unsigned char在遇到超出其数据范围的数(0~255)也会进行循环,例如256就是0了,所以最终该代码会陷入一个死循环

#include <stdio.h>
int main()
{
 unsigned int i;
 for(i = 9; i >= 0; i--)
 {
 printf("%u\n",i);
 }
 return 0;
}

有了前两个代码的铺垫,不难想出,这个也会陷入死循环,当i=-1时,由于i是unsigned int类型(0~4 294 967 295),所以不存在负数,就会变成了4 294 967 295
在这里插入图片描述

由以上几个代码我们知道,整型数据(基本整型、短整型、长整型、双长整型、字符型等)其实都遵循一个循环过程,对超出其范围的数据会变成另一个数(注意:当你在测试是否遵循时,记得用对正确的占位符)

2.3.6 练习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;
}

通过上述小端字节序与大端字节序的学习,我们知道:
⼩端(字节序存储)模式:是指数据的低位字节内容保存在内存的低地址处,⽽数据的⾼位字节内容,保存在内存的⾼地址处。
所以,数组a中的元素在内存中的存储如下:
在这里插入图片描述

&a,这里的a代表数组名(取出的是一个数组指针,类型 — int(*)[4]),&a+1跳过一个数组,由于此时的类型是int( * )[4],所以应该强转为int *,所以最终ptr1指向图中位置,ptr1[-1]等价于 *(prt1-1),所以最终结果为4
a代表数组首元素的地址,强转为int后加+,就是普通的整型加1,所以此时ptr2指向图中位置,类型是int *,所以进行 *ptr2时,访问的是四个字节,且由于是在小端字节序模式下,所以取出结果十六进制形式为0x02000000
运行结果如下:
在这里插入图片描述

3. 浮点数在内存中的存储

常⻅的浮点数: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;
}

运行结果如下:
在这里插入图片描述
是不是与你所想完全不相同,哈哈!为什么呢
在这里插入图片描述
这里我们先来小小分析一下:
在这里插入图片描述

n是一个整型数据,取出来以整数形式打印,没半点毛病,对吧!
此时,将n的地址赋予一个float类型的指针,站在浮点型指针的角度来看,若对浮点型指针pFloat解引用,此时就要向后访问一个浮点型的空间,即4个字节,而其认为这4个字节中存储的是float类型的数据,最终取出的结果如图
由此可知,当我们以整数形式存进去,以浮点数形式取出,会造成结果与预期不同,所以,整数与浮点数在内存中的存储方式存在着差异

那么,浮点数是怎么存储的呢?

让我们了解完再回来看吧!
在这里插入图片描述

3.2浮点数的存储

上⾯的代码中, num 和 *pFloat 在内存中明明是同⼀个数,为什么浮点数和整数的解读结果会差别这么⼤?要理解这个结果,⼀定要搞懂浮点数在计算机内部的表⽰⽅法。

根据国际标准IEEE(电⽓和电⼦⼯程协会) 754,任意⼀个⼆进制浮点数V可以表⽰成下⾯的形式:
在这里插入图片描述

如何理解呢?
下面将以十进制形式的5.5为例:

5.5 --- 十进制的浮点数表示形式
这时候有人会问:能不能把5.5写成二进制形式呢?
答案是可以的。

那么如何转换呢? --- 小数点前后分别进行转换
我们知道小数点前面的5可以写成101,那么,小数点后面的5也是101么,不是的

对一个二进制数进行解读:
在这里插入图片描述

所以,5.5写成二进制应该是101.1,用科学计数法表示就是1.011* 2 2 2^{2} 22
由于该数是二进制,所以底数是2;如果是十进制的数话,如:123.45,用科学计数法表示就是1.2345* 1 0 2 10^{2} 102

IEEE(电⽓和电⼦⼯程协会) 754表示,任意⼀个⼆进制浮点数V可以表⽰成下⾯的形式:
在这里插入图片描述

所以1.011* 2 2 2^{2} 22又可以这样表示:V= ( − 1 ) 0 (-1)^{0} (−1)0 * 1.011 * 2 2 2^{2} 22;其中,S ---- 0,M ---- 1.011,E ---- 2

由于其中的(-1)与底数2都是固定的,所以浮点数的存储,其实存储的就是S、M、E相关的值

IEEE 754规定:
对于32位的浮点数(float),最⾼的1位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数字M
对于64位的浮点数(double),最⾼的1位存储符号位S,接着的11位存储指数E,剩下的52位存储有效数字M

在这里插入图片描述

3.2.1 浮点数存的过程

IEEE 754 对有效数字M和指数E,还有⼀些特别规定。
前⾯说过, 1≤M<2 ,也就是说,M可以写成 1.xxxxxx 的形式,其中 xxxxxx 表⽰⼩数部分。

比如:0.5(十进制)
二进制:0.1 —>1.0 * 2 − 1 2^{-1} 2−1

IEEE 754 规定:

在计算机内部保存M时,默认这个数的第⼀位总是1,因此可以被舍去,只保存后⾯的xxxxxx部分。⽐如保存1.01的时候,只保存01,等到读取的时候,再把第⼀位的1加上去。这样做的⽬的,是节省1位有效数字。以32位浮点数为例,留给M只有23位,将第⼀位的1舍去以后,等于可以保存24位有效数字。

⾄于指数E,情况就⽐较复杂
⾸先,E为⼀个⽆符号整数(unsigned int)(IEEE 754规定)
这意味着。如果E是8位,它的取值范围为0~255;如果E为11位,它的取值范围为 0 ~2047。但是我们知道,科学计数法中的E是可以出现负数的(比如上面提到的十进制0.5,其二级制为0.1,科学计数法表示为1.0 * 2 − 1 2^{-1} 2−1,其中E为 -1),所以IEEE 754规定,存入内存时E的真实值必须再加上一个中间数,对于8位的E,这个中间数是127;对于11位的E,这个中间数是1023。比如: 2 10 2^{10} 210的E是10,所以保存成32位浮点数时,必须保存成10+127=137,即10001001。

在这里给出一个代码帮助理解:

//大家自己在举例的时候,不要举特殊数字
//3.14
//11.0010101000010101010101010100000010000010101010010101010
//如果小数点后的位太多,就可能导致浮点数在内存中无法精确的保存


int main()
{
	//5.5
	float f = 5.5f;
	//5.5
	//101.1
	//1.011*2^2
	//(-1)^0 * 1.011 * 2^2
	//S=0
	//M=1.011
	//E=2
	//2+127=129
	//0100 0000 1011 00000000000000000000
	//40 B0 00 00
	//
	return 0;
}
下面的图可以帮助了解!

在这里插入图片描述

3.2.2 浮点数取的过程

指数E从内存中取出还可以再分成三种情况:

E不全为0或不全为1

这时,浮点数就采⽤下⾯的规则表⽰,即指数E的计算值减去127(或1023),得到真实值,再将有效数字M前加上第⼀位的1。

⽐如:0.5 的⼆进制形式为0.1,由于规定正数部分必须为1,即将⼩数点右移1位,则为1.0 * 2 − 1 2^{-1} 2−1,其阶码为-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的很⼩的数字。

0 00000000 00100000000000000000000

E全为1

这时,如果有效数字M全为0,表⽰±⽆穷⼤(正负取决于符号位s);

0 11111111 00010000000000000000000

好了,关于浮点数的表⽰规则,就说到这⾥。
接下来,让我们回到一开始的代码题吧!
在这里插入图片描述

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

注:此时针对的是32位浮点数
在这里插入图片描述

在这里插入图片描述

好了,到这里对数据在内存中的存储就结束了,希望大家都有所收获!
在这里插入图片描述

标签:11111111,存储,字节,符号,int,浮点数,char,内存,数据
From: https://blog.csdn.net/2401_82669614/article/details/136712134

相关文章

  • 插入数据库遇到中文无插入的问题 Error 1366 (HY000): Incorrect string value: ‘\x
    项目场景:beego登录注册过程中将信息写入到MYSQL数据库中问题描述字段写入过程中数据出现无法写入的情况,出现报错:Error1366(HY000):Incorrectstringvalue:‘\xE7\x94\xB7’forcolumn‘sex’atrow1原因分析:根据控制台收到的打印信息我发现数据正确从前......
  • 调用存储过程
    SqlDataAdaptersda=newSqlDataAdapter();//DataSet//查询调用存储过程需要先准备一个命令对象SqlCommandcmd=newSqlCommand("PR_selectNew",conn);cmd.CommandType=CommandType.StoredProcedure;//设置适配器SqlDataAdapter将准备......
  • 实验1 C语言开发环境使用和数据类型,运算符,表达式
    #include<stdio.h>intmain(){printf("O\n");printf("<H>\n");printf("II\n");return0;}#include<stdio.h>intmain(){printf("O\n");printf("<H>\n");print......
  • 关于数据通信知识的补充——第二篇
    目录四.二层交换机5.实现不同vlan通信的原理方法一:路由器网关方法二:单臂路由方法三:三层交换机五.三层路由技术(1)直连路由(2)静态路由(3)动态路由上一篇我们学习了用vlan隔离也可有效优化泛洪,还拉下一个不同vlan间通信的原理,现在我们接着学习。四.二层交换机5.实现不同......
  • 数据结构之有趣的扑克牌(出牌吧!!)
    题外话这不是魔法,而是科学小实验!!!请大家多多支持我,我真的真的太想进步了啊!!!!正题扑克牌代码思路1.代码分为买牌,洗牌还有发牌(三个人每个人五张牌)2.要熟练掌握javase初阶和数据结构中的ArrayList类扑克牌代码以及代码详解packageCard;importjava.util.Array......
  • 动手学习Deep learning-数据预处理
    数据预处理:importosos.makedirs(os.path.join('..','data'),exist_ok=True)#自动读取该代码文件的文件位置,并返回上级目录创建data文件data_file=os.path.join('..','data','house_tiny.csv')#创建CSV文件withopen(data_file,'w......
  • 整数和浮点数在内存中的储存(包含原反补码的讲解)
    在c语言中,我们常常使用整数和浮点数,那么你知道整数和浮点数在内存中是如何储存的吗?下面大家一起学习。文章目录一.整数在内存中的储存二.了解大小端字节序三.浮点数在内存中的储存一、整数在内存中的储存整数的二进制表示方法有三种:原码、反码、补码。有符号整数......
  • 宝宝起名网,姓名分析打分php源码带数据库带火车头免登录发布模块
    宝宝起名网源码/取名网/姓名分析/名字打分/算命测算文章系统演示地址:https://s17.ryzlk.com/手机端地址:https://m.s17.ryzlk.com/起名说明:起名内容来源数据库,通过客户提交的姓名,出生年月日表单,计算出用户的五行缺旺,然后从数据库中调用五行相符的姓名提供给客户。......
  • HMAC算法:数据传输的保护神
    title:HMAC算法:数据传输的保护神date:2024/3/1616:50:53updated:2024/3/1616:50:53tags:HMAC算法消息认证哈希函数密钥管理数据安全网络通信防篡改HMAC算法起源:HMAC(Hash-basedMessageAuthenticationCode)算法是由MihirBellare、RanCanetti和HugoKrawczyk......
  • 数据结构知识总结笔记------第四章:串(2)串的简单模式匹配算法、KMP算法、KMP算法的改进
    1、简单模式匹配算法对一个串中某子串的定位操作称为串的模式匹配,其中待定位的子串称为模式串。算法的基本思想:从主串的第一个位置起和模式串的第一个字符开始比较,如果相等,则继续逐一比较后续字符;否则从主串的第二个字符开始,再重新用上一步的方法与模式串中的字符做比较,以......