十大字符串函数与内存操作函数

news2024/11/17 17:26:49

前言:我们知道在C语言的库中有许许多多的库函数,今天我就来介绍一下自己对两大类库函数中一些常用函数的认识和理解,希望对大家有帮助。

说明:下文中会花较大篇幅实现这些库函数的模拟,请大家不要觉得库函数直接用就好了,模拟没意义。模拟实现不仅可以增强我们对库函数的理解,还能够让我们理解其中实现的原理以及我们可能忽略的一些重要细节,我会在模拟实现各行代码需要处给上注释,所以还请各位能够好好学习一下这些库函数的模拟实现。

目录

目录

一:六大常见字符串函数的操作与模拟

1. strlen函数

(1) 概述

(2) 模拟实现

2. strcpy函数

(1) 概述

(2) 模拟实现

3. strcat函数

(1) 概述

(2) 模拟实现

4.strcmp函数

(1) 概述

(2) 模拟实现

5.strtok函数

(1) 概述

(2) strtok函数的使用

6. strstr函数(重点)

(1) 概述

(2) strstr函数的使用

(3) 模拟实现strstr函数

(4) 小题一道:

二:四大内存操作函数的介绍与模拟

1. memcpy函数

(1) 概述

(2) memcpy函数的使用 

(3) memcpy函数的模拟实现

2. memmove函数

(1) 概述

(2) memmove函数的使用 

(3) memmove函数的模拟实现

3. memcmp函数

(1) 概述

(2) memcmp函数的使用与模拟

4. memset函数

(1) 概述

(2) memset函数的使用


一:六大常见字符串函数的操作与模拟

先说明一下:下列这些库函数的使用都需要引用头文件<string.h>,并且希望各位在使用以及模拟实现的过程中打开监视窗口,多多调试看内部的变化,一定会有不一样的收获。

1. strlen函数

(1) 概述

我首先来介绍一下strlen函数:

1. 定义: size_t strlen( const char *string )

2. 返回值:这个函数返回字符串中的字符数,不包括终端的NULL('\0')

3. 参数:由定义知道这个函数的的参数是 string, 其表示一个以空值('\0')结尾的字符串

4. 作用:获取字符串的长度

(2) 模拟实现

strlen函数相对简单,这里不做过多说明,下面用两种不同的方法实现对其的模拟应用。

/*int my_strlen(const char* arr)//方法(1)——计数器
{
    assert(arr != NULL);//断言arr不为空指针,防止下列代码出错(先直接应用)
	int count = 0;
	while (*arr != '\0')
	{
		count++;
		arr++;
	}
	return count;
}*/

int my_strlen(char* arr)//方法(二)——函数递归
{
    assert(arr != NULL);
	if (*arr != '\0')
		return 1 + my_strlen(arr + 1);
	else
		return 0;
}

int main()//strlen函数实现的中心思想是指向首元素的指针不断后移,找字符串末尾的'\0'
{
	char arr[10] = "ABCDEF";
	int ret = my_strlen(arr);
	printf("%d\n", ret);
	return 0;
}

2. strcpy函数

(1) 概述

接下来介绍的是strcpy函数了,其作用是拷贝字符串,下表详细介绍

1. 定义: char *strcpy( char* strDestination, const char* strSource )

2. 返回值:这个函数返回目标字符串(strDestination)起始位置的地址

3. 参数:

strDestinationstrSource
目标字符串以'\0'结尾的源字符串
4. 作用:将 源字符串strSource(包括终止空字符‘\0’)复制到 目标字符串strDestination 指定的位置。如果源字符串和目标字符串重叠,则未定义 strcpy 的行为。

(2) 模拟实现

char* my_strcpy(char* dest, const char* sour)
{
	assert(dest && sour);
	char* ret = dest;//存放dest指针的起始状态,以便返回

//(strcpy函数返回的是目标字符串的起始地址),返回值的设定是为了实现链式访问)
//链式访问eg: printf("%s\n", my_strcpy(arr1, arr2))

	/*while (*sour != '\0')//1.普通思路                                        
	{
		*dest = *sour;
		dest++;
		sour++;
	}
	*dest = '\0';*/

	while (*dest++ = *sour++)//2.简洁代码(后置加加,先将*sour赋值给*dest,再将指针后移)
	{
		;  //循环条件表达式结果为0('\0')时,跳出循环,并且也将'\0'拷贝了,十分巧妙
	}
	return ret;
}

int main()//实现思想:将源字符串的元素依次拷贝到目标字符串中,拷贝完'\0'后终止
{
	char arr1[10] = "XXXXXXX";
	char arr2[10] = "ABCDEFGE";
	my_strcpy(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

注意:strcpy函数会将源字符串末端的'\0'也拷贝到目标字符串。

3. strcat函数

(1) 概述

接下来介绍的是strcat函数了,其与strcpy函数十分相似,下表详细介绍

1. 定义:char *strcat( char *strDestination, const char *strSource )

2. 返回值:这个函数返回目标字符串(strDestination)起始位置的地址

3. 参数:

strDestinationstrSource
目标字符串以'\0'结尾的源字符串

4. 作用:strcat函数将 源字符串strSource追加(可以理解为拷贝)到目标字符串strDestination,并用空字符('\0')终止生成的字符串。strSource 的初始字符会覆盖 strDestination 的终止空字符。

5. 说明:这里有一点要强调的是,如果使用strcat函数时用字符串自己的内容给自己追加时(即strcat(arr1,arr1)),会导致Bug的发生,故这里提醒一下如果要对字符串追加自己的一部分时,strcat不适用,但是可以使用函数strncat,这里不具体讲解(留给大家自己去了解),但是下面在讲完函数strstr后会展示一道与其有关的小题,大家可以了解一下。

(2) 模拟实现

char* my_strcat(char* dest, const char* sour)
{
	assert(dest && sour);
	char* ret = dest;//存放首地址作为返回值
	while (*dest)
	{
		dest++;//寻找目标字符串的'\0'
	}
	while (*dest++ = *sour++)//找到后开始追加,与strcpy相似
	{
		;
	}
	return ret;
}

int main()
{
	char arr1[20] = "abcdef";//目标空间要足够大!!!
	char arr2[10] = "ABC";
	my_strcat(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

注意:源字符必须以'\0'结束;目标空间足够大并且可修改(不能是常量字符串)。

4.strcmp函数

(1) 概述

接下来介绍的是strcmp函数了,下表详细介绍

1. 定义:int strcmp( const char* string1, const char* string2 );

2. 返回值:这个函数的返回值是一个整数,指示字符串 1 与字符串 2 的字典关系 (字符串逐字母比较)

    注意:VS编译器下,< 0对应值规定为 -1,> 0对应的值规定为 1。

返回值字符串关系
  < 0 str1 <str2
   0str1 = str2
  > 0str1 > st2
3. 参数:
    string1   string2

要比较的以'\0'结尾的字符串

要比较的以'\0'结尾的字符串

4. 作用:strcmp函数可以对两个以'\0'结尾的字符串进行比较

(2) 模拟实现

int my_strcmp(const char* arr1, const char* arr2)
{
	assert(arr1 && arr2);
	while (*arr1 == *arr2)首字母相等
	{
		if (*arr1 == '\0')//两字符串都为空字符串或首位均为'\0'
		{
			return 0;
		}
		arr1++;
		arr2++;//继续向后比较
	}
	return (*arr1 - *arr2);//不相等直接返回差值判断大小
}

int main()
{
	char arr1[10] = "azed";
	char arr2[10] = "azee";
	int ret = my_strcmp(arr1,arr2);
	printf("%d\n", ret);
	return 0;
}

注意:我在此再次说明一下,在VS编译器下,< 0对应返回值规定为 -1,> 0对应返回值规定为 1;但是我在模拟实现的过程中没有单纯的以VS环境下编写。

5.strtok函数

(1) 概述

接下来介绍的是strtok函数了,下表详细介绍

1. 定义:char *strtok( char* strToken, const char* strDelimit )

2. 返回值:被分割字符串的首元素地址

3. 参数:

        strToken     strDelimit

包含标志(分隔)符的字符串

分隔符集(自己定义的)

4. 作用:当遇到分隔符时会将之前的字符串分割并将该分隔符替换成NULL

(2) strtok函数的使用

int main()
{
	char arr[] = "ab.cd,sedr@dsf";//strToken
	const char* Del = ",.@";//strDelimit

	char* ret = strtok(arr, Del);
	for (ret;ret != NULL;ret = strtok(NULL, Del))
 //将分隔符转换成NULL后再将此位置作为起始位置继续向后找分隔符
	{
		printf("%s\n", ret);//打印出所有被分割的字符串
	}
	return 0;
}

6. strstr函数(重点)

相较于上面五个函数而言,我觉得strstr函数是最重要也是模拟实现起来最难的一个,据我现在了解,它的实现与我们后面要学习的一些知识有关,还请各位重视起来,接下来就要开始介绍它了。

(1) 概述

1. 定义:char *strstr( const char* string, const char* strCharSet )

2. 返回值:这个函数返回一个指针,指向string字符串中第一次出现的strCharSet首字符的位置,如果 strCharSet 未出现在字符串中,则返回 NULL。如果 strCharSet 指向长度为零的字符串,则该函数返回string字符串。

3.参数:

                string           strCharSet
要搜索的以'\0'结尾的字符串(相当于母串)要查找的以'\0'结尾的字符串(相当于子串)

4. 作用:在字符串string中查找字符串strCharSet

(2) strstr函数的使用

int main()
{
	char arr1[10] = "abbbcdef";  //string
	char arr2[5] = "bbc";  //strCharSet
	char* ret = strstr(arr1, arr2);  //在"abbbcdef"中查找"bbc"
	if (ret == NULL)  //查不到子串就返回NULL
	{
		printf("找不到了\n");
	}
	else
	{
		printf("%s\n", ret);//找到了返回一个字符指针,打印从该位置开始的字符串
	}
	return 0;
}

 (3) 模拟实现strstr函数

char* my_strstr(char* str1, char* str2)
{
	assert(str1 && str2);
	char* s1 = str1;
	char* s2 = str2; 
//str1与str2作为一个起点,不移动,能够使s1,s2在匹配过程中未完全成功时返回初始位置重新开始匹配

    char* cur = str1;  //cur用来记录匹配成功的起始位置!!!
	while (*cur)  //*cur=='\0'时目标字符串遍历完毕,跳出循环
	{
		s1 = cur;  //与cur++搭配使用,使得首位匹配失败后能继续向后匹配(或)匹配了但未成功,将s1退回到开始匹配处的后一位(cur+1)

		s2 = str2;  //匹配了但未成功,将s2回归首位重新进行匹配
		while (*s1 == *s2) //匹配首位成功后继续向后匹配
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')//子串移动到\0处即匹配成功,返回匹配的起始位置(cur)
		{
			return cur;
		}
		cur++;  //与(char* cur = str1)配合,每次匹配不成功就将s1后移一位
	}
	return NULL;
}

int main()
{
	char arr1[10] = "abbbcdef";
	char arr2[5] = "bbc";
	char* ret = my_strstr(arr1, arr2);  //在"abbbcdef"中查找"bbc"
	if (ret == NULL)  //查不到子串就返回NULL
	{
		printf("找不到了\n");
	}
	else
	{
		printf("%s\n", ret);
	}
	return 0;
}

这个模拟实现只是在一个字符串中查找另一个字符串的经典普通的实现方法,还有一种较为高效的实现方法——KMP算法,有兴趣的可以去了解一下。这样我对这个函数的理解分享就到这里结束了,希望对大家有帮助。

(4) 小题一道:

写一个函数,判断一个字符串是否为另外一个字符串旋转之后的字符串

eg:

1.AABCD左旋一个字符得到ABCDA

2.AABCD左旋两个字符得到BCDAA

3.AABCD右旋一个字符得到DAABC

int Is_turn(char* arr1, char* arr2)
{
	assert(arr1 && arr2);
	int len1 = (int)strlen(arr1);
	int len2 = (int)strlen(arr2);
	if (len1 != len2)//长度不等时一定不满足条件
		return 0;
	strncat(arr1, arr1,len1);//用strncat在arr1后面追加一个arr1
	char* ret = strstr(arr1, arr2);//追加完后,如果arr2是arr1的字串,则arr2一定是由arr1旋转得到的
	if (ret == NULL)
		return 0;
	else
		return 1;
}

int main()//应用strstr与strncat函数
{
	char arr1[20] = "AABCD";
	char arr2[20] = "ABCDA";
	int ret = Is_turn(arr1, arr2);
	if (ret == 1)
		printf("yes\n");
	else
		printf("no\n");
	return 0;
}

这是实现这道题的一种比较好的方法,利用到了这篇文章中讲到的两个库函数,如果你用正常的思路去写这个代码的话,会复杂很多。

我对这些常用的字符串操作函数就介绍到这里,希望大家可以好好理解一下,同时有问题的地方也请各位能在评论区留言,我们一起进步,谢谢大家。接下来就是对三个内存操作函数的介绍了。

二:四大内存操作函数的介绍与模拟

接下来就是对四个内存操作函数(memcpy,memmove,memcmp,memset)的介绍了。

提示:由于这是内存操作函数,所以在调试过程中观察内存变化十分重要,我也会对内存的变化进行一定的展示,但最重要的还是各位自己调试感受一下。

1. memcpy函数

(1) 概述

这个函数与strcpy相似,区别在于它规定了具体拷贝的字节数,下面具体说明:

1. 定义:void *memcpy( void *dest, const void *src, size_t count )

2. 返回值:memcpy返回指针dest(指向dest字符串的起始位置)

3. 参数:

        dest              src                count
    新的缓冲区

  要从中复制的缓冲区

   要复制的字符(字节)数

4. 作用:memcpy 函数将 src 的计数字节(即count,由使用者自己决定)复制到 dest。

(2) memcpy函数的使用 

内存变化展示:

memcpy函数调用前:

 memcpy函数调用后:

告诫:能够清晰的观察前后两次变化的前提条件是知道调试和小端存储的概念。

 观察分析前后两次变化可以知道,memcpy函数是逐字节复制实现其功能的,知道这个后我们就可以很好的对其进行模拟实现了。

(3) memcpy函数的模拟实现

void* my_memcpy(void* dest, const void* src, size_t count)//void*类型可以接收所有类型的指针
{
	assert(dest && src);
	void* ret = dest;//保存返回值
	while (count--)
	{
		*(char*)dest = *(char*)src; //强制转换成char*类型,解引用后访问一个字节
		dest = (char*)dest + 1;
		src = (char*)src + 1; //dest,src指针都后移一个字节继续将src的内容复制到dest中
	}
	return ret;
}

int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0x11111111,0x22222222,0x33333333,0x1144 };//0x表示16进制数
	int sz = sizeof(arr1) / sizeof(arr1[0]);
	my_memcpy(arr2, arr1, 13);
	int i = 0;
	for (i = 0;i < sz;i++)
	{
		printf("%d ", arr2[i]);
	}
	return 0;
}

注意:这个模拟实现无法完成对两个有重叠部分字符串的拷贝(主要是自己对自己复制)(下面还会介绍)。

执行结果:

到这里,我对memcpy函数的介绍就结束了,但是还有一点是,在memcpy函数出现的早期,其无法完成对有重叠部分的两个字符串的拷贝,所以出现了另一个完善这个功能的函数——memmove,其作用与memcpy几乎完全一致(在当前编译器下已经一样了),接下来就来介绍一下这个函数。

2. memmove函数

(1) 概述

1. 定义:void *memmove( void *dest, const void *src, size_t count )

2. 返回值:memcpy返回指针dest(指向dest字符串的起始位置)

3. 参数:

        dest           src                      count
      目标对象         源对象

           要复制的字符(字节)数

4. 作用:memmove 函数将count个字节数从 src 复制到 dest。如果源区域(src)的某些区域与目标区域(dest)重叠,memmove 可确保在覆盖之前复制重叠区域中的原始字节(即可以实现对重叠部分的复制)。

(2) memmove函数的使用 

(3) memmove函数的模拟实现

这个函数的模拟实现是基于memcpy函数模拟实现之上的,我们需要考虑的就是如何使重叠部分也完成拷贝。

画图分析:

如图,当源空间的起始位置指向3时,向后拷贝五个整型数据(20个字节)到目标空间时,目标空间的起始地址有以下三种情况,同时对应着三种不同的拷贝方式:

1. 当dest位于dest1左边时,要使拷贝不覆盖,就要以源空间首元素3的第一个字节为起点并且不断后移,将各个字节拷贝到目标空间的对应字节处。

2. 当dest位于dest1与dest2之间时,由分析可知,要使拷贝不覆盖,就要以源空间末元素7的最后一个字节为起点并且不断前移,将各个字节拷贝到目标空间的对应字节处。

3. 当dest位于dest2的右边时,很显然,无论从左向右拷贝还是从右向左拷贝,只要确认好起点,将源空间的字节逐个拷贝到目标空间的对应字节处即可。

这里为了方便实现,我将方式2与方式3并为一种(即都是从右向左拷贝),而方式一则不同(从左向右拷贝),当然还有另一种思路大家可以自己思考实现一下。

代码实现及相关注释:

void* my_memmove(void* dest, const void* src, size_t count)
{
	assert(dest && src);
	void* ret = dest;//保存返回值
	if (dest < src)//从左向右拷贝
	{
		while (count--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;//强转为char*,解引用后逐字节拷贝
		}	
	}
	else//从右向左拷贝
	{
//在一串连续的数据中,要从第一个字节跳转到最后一个字节,就让第一个字节的地址加上(数据总字节数-1)
		while (count--)//所以这里count进入循环时恰好是(count-1),使得跳转到空间的最后一个字节
		{
			*((char*)dest + count) = *((char*)src + count);
		} 
	}//count在循环中一直减1,使指针从两空间的最后一个字节处不断前移,完成逐字节拷贝
	return ret;
}

int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int sz = sizeof(arr1) / sizeof(arr1[0]);
	my_memmove(arr1 + 2, arr1, 20); //对自己的一部分(将3,4,5,6,7改成1,2,3,4,5)进行拷贝更改
	int i = 0;
	for (i = 0;i < sz;i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

这样,memmove函数的模拟实现就结束了。

3. memcmp函数

(1) 概述

这个函数与strcmp相似,区别在于它规定了进行比较的字节数,下面具体说明:

1. 定义:int memcmp( const void *buf1, const void *buf2, size_t count )

2. 返回值:memcpy返回一个表示buf1与buf2关系的值

 返回值  两空间关系
    < 0   buf1 <buf2
     0  buf1 = buf2
    > 0  buf1 > buf2

3. 参数:

         buf1           buf2                      count
       缓冲区1         缓冲区2

           要进行比较的字符(字节)数

4. 作用:memcmp函数从 buf1 和 buf2 的第一个计数字节开始进行比较,若相等则继续向后一字节进行比较,直至某字节大小不同或比较了count字节,并返回一个指示它们关系的值。

(2) memcmp函数的使用与模拟

int my_memcmp(void* arr1, void* arr2, int count)
{
	assert(arr1 && arr2);

	char* s1 = arr1;
	char* s2 = arr2;
	while (*s1 == *s2 && --count)//(--count):比较一个字节时不用移动s1与s2
	{
		s1++;
		s2++;
	}
	return *s1 - *s2;
}
int main()
{
	int arr1[5] = { 1,2,3,5,1 };
	int arr2[5] = { 1,2,3,5,257 };//要知道十进制怎么转为十六进制(可以在调试过程中认真分析)
	//int ret = memcmp(arr1, arr2, 17);
	int ret = my_memcmp(arr1, arr2, 17);
	printf("%d\n", ret);
	return 0;
}

4. memset函数

(1) 概述

1. 定义:void *memset( void *dest, int c, size_t count );

2. 返回值:memset 返回 dest 的值。

3. 参数:

                dest             c               count
    指向起始位置的指针   要设置的字符    要设置的字符(字节)数
 4. 作用:  memset函数可以将指针dest指向的目标空间的count个字节数设置为字符c。

(2) memset函数的使用

 

 结语

这样,我就把六个字符串操作函数与四个内存操作函数介绍完了,内容还是比较丰富且重要的。总结完后我自己是收获满满的,也希望各位可以认真阅读一番,得到一些不一样的收获。再见,各位。

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

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

相关文章

UNet入门总结

作者&#xff1a;AI浩 来源&#xff1a;投稿 编辑&#xff1a;学姐 Unet已经是非常老的分割模型了&#xff0c;是2015年《U-Net: Convolutional Networks for Biomedical Image Segmentation》提出的模型。 论文连接&#xff1a;https://arxiv.org/abs/1505.04597 在Unet之前…

Android 深入系统完全讲解(4)

4 SystemServer 创建过程 SystemServer 进程非常关键了&#xff0c;我们上层的服务都是在这里以线程的形式存在&#xff0c;比如 AMS&#xff0c;PMS&#xff0c;WindowManagerService&#xff0c;壁纸服务&#xff0c;而关于调试这个服务进程&#xff0c;我们随后就会讲到。 …

虚拟人-面部表情-Audio2Face语音驱动表情

任务&#xff1a; 输入自己的音频&#xff0c;导入maya模型&#xff0c;让maya模型通过音频驱动说话 教程&#xff1a; https://www.bilibili.com/video/BV1rZ4y1R7H4/?p2&spm_id_frompageDriver&vd_sourceef114f70c3fd4d5394f12dbd3d022bbe 一.下载和安装 1.首先…

Java面试常见问题-SE篇

JavaSE面试问题汇总①int和Integer的区别为什么设计封装类型&#xff1f;JDK、JRE、JVM的区别和equals方法的区别hashCode()与equals()之间的关系泛型中extends和super的区别String、StringBuffer、StringBuilder的区别重载和重写的区别接口和抽象类的区别List与Set的区别Array…

2023/1/8总结

今天学了了强连通算法 Tarjan算法 Tarjan算法是一种求解有向图强连通分量的线性时间的算法&#xff0c;他运用到了DFS算法以及DFS的特性和数据结构——栈。 算法介绍&#xff1a;如果两个顶点可以相互通达&#xff0c;则称两个顶点强连通(strongly connected)。如果有向图G…

LeetCode题解 二叉树(十三):701 二叉搜索树的插入操作;450 删除二叉搜索树中的结点

701 二叉搜索树的插入操作 medium 给定二叉搜索树&#xff08;BST&#xff09;的根节点和要插入树中的值&#xff0c;将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据保证&#xff0c;新值和原始二叉搜索树中的任意节点值都不同。 如果要按照题目中所说改变二叉…

渗透测试中的常用编码

渗透测试中的常用编码 页面编码 在网页设置网页编码 在中加入设置特定html标签 这样页面的编码就会变成utf-8 &#xff0c;如果没有设置编码就会使用默认 的编码&#xff0c;而浏览器默认编码与之不同就会出现乱码。 常用的有三种格式分别是 utf-8、gbk、gbk2312 ascii编码…

_Linux 进程信号-信号处理篇

文章目录前言捕捉信号1. 内核如何实现信号的捕捉2. sigaction代码验证可重入函数volatile(关键字)SIGCHLD信号实验一实验二前言 信号发送 信号处理 已经讲过&#xff0c;本章讲解信号处理最后一部分。 捕捉信号 信号捕捉过程图 经过信号捕捉过程图&#xff1a;我们知道信号…

语音文件分析

语音文件格式的重要参数 语音波形,它的这个文件,主要的格式就是采样率,那么电话或者嵌入式设备,采样率一般是8000Hz,就一秒钟8000个点,如果是PC机麦克风,那是16K,就一秒钟是16000个点,像这个CD是高保真的,音乐唱片的是用这个44.1K。 量化位数,又叫采样精度,…

绿通科技在创业板通过注册:收入依赖美国市场,张志江为实控人

2023年1月6日&#xff0c;证监会发布关于同意广东绿通新能源电动车科技股份有限公司&#xff08;下称“绿通科技”或“绿通电动车”&#xff09;、杭州国泰环保科技股份有限公司首次公开发行股票注册的批复。换句话说&#xff0c;证监会同意上述两家公司的创业板IPO注册。 同日…

【手写 Vue2.x 源码】第十一篇 - Vue 的数据渲染流程

一&#xff0c;前言 上篇&#xff0c;主要介绍了数组数据变化的观测情况&#xff0c;涉及以下几个点&#xff1a; 实现了数组数据变化被劫持后&#xff0c;已重写原型方法的具体逻辑&#xff1b;数组各种数据变化时的观测情况分析&#xff1b; 目前为止&#xff0c;数据劫持…

webpack 如何编写 loader

三种本地开发测试 loader 的方法 1. 匹配&#xff08;test&#xff09;单个 loader 你可以通过在 rule 对象使用 path.resolve 指定一个本地文件&#xff1a; webpack.config.js const path require(path);module.exports {//...module: {rules: [{test: /\.js$/,use: [{…

Ansible Automation Platform - 在 RHEL 安装 Ansible Automation Platform 2.3 环境

《OpenShift / RHEL / DevSecOps 汇总目录》 文本已在 RHEL 9 AAP 2.3 环境中进行验证。 说明&#xff1a; 本文介绍如何在一个节点上部署一套 all-in-one 的 Ansible Automation Platform 2.3 的运行环境。红帽 Ansible Automation Platform 2.3 需要至少 RHEL 8.4 以上的环…

【EHub_tx1_tx2_E100】Ubuntu18.04 + ROS_ Melodic + Velodyne VLP-16雷达 测试使用

简介&#xff1a;介绍 Velodyne VLP-16 16线激光雷达 在EHub_tx1_tx2_E100载板&#xff0c;TX1核心模块环境&#xff08;Ubuntu18.04&#xff09;下测试ROS驱动&#xff0c;打开使用RVIZ 查看点云数据&#xff0c;本文的前提条件是你的TX1里已经安装了ROS版本&#xff1a;Melod…

HashMap、HashTable、ConcurrentHashMap之间的区别及常见面试题

Java集合类有的集合类是存在线程安全的问题&#xff0c;但是由于之前对于集合类的使用都是在单线程的情况下使用的&#xff0c;不没有在多线程环境下使用&#xff0c;所以不涉及线程安全的问题&#xff1b;这篇博客着重讲解一下多线程环境下使用哈希表。HashMapHashMap本身不是…

一些开发时常用的网站或命令

目录关于gitgit下载网址git安装教程Gortoisegit下载地址关于PythonAnyWhere关于Linux压缩与解压命令关于python的相对与绝对路径使用_\_file_\_实现跨平台关于宝塔面板关于浏览器驱动下载本博客首次编辑于2023.01.04 &#xff0c;后续将持续进行更新 关于git git下载网址 gi…

Linux - 系统文件目录说明

目录/ - 根目录/bin - 用户基础二进制文件目录/boot - 静态启动文件/dev - 设备文件/etc - 配置文件/home - 主目录/lib - 基础共享库/lib64 - 64位基础共享库/lostfound - 可恢复的文件/media - 可移动媒体/mnt - 临时挂载点目录/opt - 自选软件包/proc - 内核 & 进程文件…

【Node】事件循环机制

Node 中的异步 API 定时器&#xff1a;setTimeout、setIntervalI/O 操作&#xff1a;文件读写、数据库操作、网络请求…Node 独有的 API&#xff1a;process.nextTick、setImmediate 事件循环的流程 Node 的事件循环分为 6 个阶段&#xff0c;这 6 个阶段会按顺序反复运行运行…

高并发内存池项目

文章目录一、项目介绍二、什么是内存池2.1 池化技术2.2 内存池2.3 内存池的作用2.4 malloc三、设计定长内存池四、高并发内存池整体框架设计六、threadcache6.1 threadcache整体设计6.2 threadcache哈希桶映射对齐规则6.3 编写对齐和映射的相关函数6.4 编写ThreadCache类6.5 th…

电网头条知识竞赛题库答案(自动答题)

今天教你们自动完成2023年电网头条的知识竞赛&#xff0c;小编也为大家安排好了教程&#xff0c;首先呢需要知道电网助手&#xff0c;打开电网助手网页https://wwwl.lanzouw.com/b01w803yj 为了帮到大家&#xff0c;我特地分享出来&#xff0c;希望能给大家带来一丝丝便利&…