【逐步剖C】-第九章-字符串函数和内存函数

news2024/12/25 12:13:26

前言:第一部分先简单介绍一下常用字符串函数和内存函数,第二部分再重点介绍重要函数的的模拟实现。若日后再发现某些好用或者有意思的库函数,都会在本文中进行更新。

一、常用库函数介绍

1. strlen

(1)函数声明

size_t strlen ( const char * str );

(2)函数介绍

  • 字符串以 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包含 ‘\0’ )。
  • 参数指向的字符串必须要以 '\0' 结束。
  • 注意函数的返回值为size_t,是无符号
    一个容易犯的使用错误,请看:
#include <stdio.h>
int main()
{
	const char*str1 = "abcdef";
	const char*str2 = "bbb";
	if(strlen(str2)-strlen(str1)>0)
	{
		printf("str2>str1\n");
	}
	else
	{
		printf("srt1>str2\n");
	}
	return 0;
}

结果看似会输出str1 > str2,但实际输出的是str2 > str1
解释strlen(str2)的结果为3,strlen(str1)的结果为6,3 - 6的结果若用整型表示确实是-3,但strlen函数的返回值为无符号整型,而从无符号的视角来看,-3的原码、反码和补码相等,故直接将-3转换为对应的十进制数,这将是一个非常大的正数,故最终输出结果为str2 > str1

2. strcpy

(1)函数声明

char* strcpy(char * destination, const char * source );

(2)函数介绍

  • 函数的功能是:将source指向的字符串中的内容拷贝到指针destination中并返回。
  • 源字符串(source指向的字符串)必须以 '\0' 结束。
  • 函数会将源字符串中的 '\0' 拷贝到目标空间。
  • 目标空间(destination指向的空间)必须足够大,以确保能存放源字符串。
  • 目标空间必须可变。

3. strcat

(1)函数声明

char * strcat ( char * destination, const char * source );

(2)函数介绍

  • 函数的功能是:将source指向的字符串中的内容追加到指针destination中并返回。
  • 源字符串(source指向的字符串)必须以 '\0' 结束。
  • 目标空间(destination指向的空间)必须足够大,以确保能追加源字符串的内容。
  • 目标空间必须可修改
  • 注意当字符串需要自己给自己追加时,不能使用这个函数。因为字符串中原来的结束条件'\0'会被覆盖。后面会在模拟实现部分进一步说明。

4. strcmp

(1)函数声明

int strcmp ( const char * str1, const char * str2 );

(2)函数介绍

  • 函数的功能是:对两个字符串中的内容进行逐字符比较,以整数的形式放回比较的结果
  • 标准规定返回的结果为:
    第一个字符串大于第二个字符串,则返回大于0的数字
    第一个字符串等于第二个字符串,则返回0
    第一个字符串小于第二个字符串,则返回小于0的数字

5. strncpy

(1)函数声明

char * strncpy ( char * destination, const char * source, size_t num );

(2)函数介绍

  • 函数的功能是:在函数strcpy的基础上实现可指定拷贝的字节数,即从源字符串拷贝num个字符到目标空间。
  • 如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边继续拷贝0('\0'),直到num个

6. strncat

(1)函数声明

char * strncat ( char * destination, const char * source, size_t num );

(2)函数介绍

  • 函数的功能是:在函数strcpy的基础上实现可指定追加的字节数,即从源字符串追加num个字符到目标空间。
  • 若追加的字节数大于源字符串的长度,则以源字符串为基准,即源字符串中的'\0'为最后一个追加的字符

7. strncmp

(1)函数声明

int strncmp ( const char * str1, const char * str2, size_t num );

(2)函数介绍

  • 函数的功能是:在函数strcmp的基础上实现可指定比较的字节数
  • 这里无需过度关注比较的字节数是否超过了两个字符串的长度,因为最多在比较到最长那一个字符串的结束标志'\0'时,一定会得出比较的结果。

8. strstr

(1)函数声明

char * strstr ( const char *str1, const char * str2);

(2)函数介绍

  • 函数的功能是:在主串(str1)中匹配子串(str2),若匹配成功则返回子串在主串的位置(第一个匹配的字符的地址,通过该地址能得到主串后面所有的内容),若匹配失败则返回一个空指针。
    如:str1:abbcdaada;str2:cda;调用函数后返回cdaada

9. strtok

(1)函数声明

char * strtok ( char * str, const char * sep );

(2)函数介绍

  • 函数的功能是:将一个带有指定分隔符的字符串,以分隔符为基准,将一个字符串分成多个字符串。
  • sep参数是个字符串,定义了用作分隔符的字符集合
  • 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标
  • strtok函数找到str中的一个标记后会将其替换为'\0',并返回一个指向以该'\0'为结束标志的字符串的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
  • 当strtok函数的第一个参数不为 NULL 时 ,函数将找到str中的第一个标记,strtok函数内部将保存它在字符串中的位置,以便函数自身进行进一步地查找。
  • 当strtok函数的第一个参数为 NULL 时,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
  • 如果字符串中不存在更多的标记,则返回 NULL 指针。

(3)使用示例

int main()
{
    char* p = "abc@def#ghi$jk";
    const char* sep = "#$@";
    char arr[30];
    char* str = NULL;
    strcpy(arr, p);//将数据拷贝一份,处理arr数组的内容
    for (str = strtok(arr, sep); str != NULL; str = strtok(NULL, sep))
    {
        printf("%s\n", str);
    }
}

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

说明:一般通过for循环来使用这个函数,因为在使用时第一次需要传需查找的字符串的地址,往后几次传的则是空指针。
第一次循环:arr中字符串的内容变为"abc\0def#ghi$jk",返回字符串"abc\0"的地址;
第二次循环:arr中字符串的内容变为"abc\0def\0ghi$jk",返回字符串"def\0"的地址;
第三次循环:arr中字符串的内容变为"abc\0def\0ghi\0jk",返回字符串"ghi\0"的地址;
第四次循环:arr中字符串的内容为"abc\0def\0ghi\0jk",返回字符串"jk\0"的地址;

10. strerror

(1)函数声明

char * strerror ( int errnum );

(2)函数介绍

  • 函数的功能是:返回错误码所对应的错误消息的字符串的地址,通过打印函数即可输出错误信息。
    C语言的库函数在运行的时候,如果发生错误,就会将错误码存在一个变量中,这个变量是:errno;错误码是一些数字:1 2 3 4 5 不同的错误码对应不同的错误信息,如:
#include <stdio.h>
int main()
{
	printf("%s\n", strerror(0));
	printf("%s\n", strerror(1));
	printf("%s\n", strerror(2));
	printf("%s\n", strerror(3));
	printf("%s\n", strerror(4));
	printf("%s\n", strerror(5));

	return 0;
}

输出结果:
在这里插入图片描述
上面的代码段仅展示用,如上述,错误码其实是存储在变量errno中,所以实际在使用时,是errno直接作为函数strerror的参数,请看:
(3)使用示例:

#include <stdio.h>
int main()
{
	//打开文件
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}

	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

若没有相关文件,程序运行结果就为:
在这里插入图片描述

11. memcpy

(1)函数声明

void * memcpy ( void * destination, const void * source, size_t num );

(2)函数介绍

  • 函数的功能是:从source的位置开始向后复制num个字节的数据到destination的内存位置。
  • 内容的拷贝是逐字节进行的。
  • 这个函数在遇到 ‘\0’ 的时候并不会停下来。
  • 如果source和destination有任何的重叠,复制的结果都是未定义的,即无法自身拷贝自身。

12. memmove

(1)函数声明

void * memmove ( void * destination, const void * source, size_t num );

(2)函数介绍

  • 和memcpy的区别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
  • 如果源空间和目标空间出现重叠,就得使用memmove函数处理

13. memcmp

(1)函数声明

int memcmp ( const void * ptr1, const void * ptr2, size_t num );

(2)函数介绍

  • 函数的功能是:比较从ptr1和ptr2指针开始的num个字节
  • 标准规定返回的结果为:
    第一个指针中的内容大于第二个指针中的内容,则返回大于0的数字
    第一个指针中的内容大于第二个指针中的内容,则返回0
    第一个指针中的内容大于第二个指针中的内容,则返回小于0的数字

14. memset

(1)函数声明

void *memset( void *dest, int c, size_t count );

(2)函数介绍

  • 函数的功能是:将目标空间(dest)中的内容,根据给定的字节数(count)改为指定的内容(c)
  • 需要注意的是,该函数是以字节为单位进行更改的。
    若写成如下形式,就会出现问题,请看:
int arr[10] = {0};
memset(arr,1,40);

代码的本意是将arr中的元素全置为1,但实际效果是将每个元素的每个字节都置为了1,及十六进制下每个元素的值为01 01 01 01,转换为十进制将会是一个比较大的数。
通过调试我们可以清楚看到:
在这里插入图片描述

  • 所以一般都以0作为指定更改的内容

二、重要库函数的模拟实现

前言:在了解了一些库函数的用法后,去尝试模拟实现还是比较有价值的,就像阅读一本书其实就是在和作者交流一样,尝试模拟实现库函数就像和函数设计者对话,感受他们在编写函数时所展现出的编程思想。那么,让我们开始吧。

1. 模拟strlen

(1)实现思路:根据上面对函数功能的介绍,我们只需统计一个字符串中'\0'之前出现的字符的次数即可。而统计的方法具体又可以分为三种:

  • 创建计数变量,利用循环进行计数,直到遇到’\0’循环停止,返回计数变量;
  • 利用递归,只要字符串中当前字符不是’\0’,则进行递归调用,即返回当前字符加上下一次递归调用的结果,即:return (1 + sim_strlen(str+1))(PS:其中str为字符串,sim_strlen为模拟的函数)
  • 创建一个指针,通过循环找到’\0’后进行指针的相减运算来得到两指针间的元素个数。
    (2)实现代码如下,请看:
//1	循环迭代的方法
size_t sim_strlen1(const char* str)
{
	assert(str);
	int count = 0;
	while (*str)
	{
		count++;
		str++;
	}
	return count;
}

//2	递归调用
size_t sim_strlen2(const char* str)
{
	assert(str);
	if (*str)
		return sim_strlen2(str + 1) + 1;
	else
		return 0;
}

//3	指针相减
size_t sim_strlen3(const char* str)
{
	assert(str);
	const char* p = str;
	while (*p++)
	{
		;
	}
	return (p - str - 1);
}

2. 模拟strcpy

(1)实现思路:根据对函数功能的描述,进行对源字符串(source)中字符的逐个拷贝,考虑到对最后'\0'的拷贝,我们可以将赋值语句直接作为循环的条件,具体请看实现代码:
(2)实现代码

char* sim_strcpy(char* destination, const char* source)
{
	char* ret = destination;
	assert(destination && source);
	while (*destination++ = *source++)
	{
		;
	}
	return ret;
}

说明:我们直接将赋值语句*destination++ = *source++作为了循环的条件,这样就能在末尾'\0'的拷贝完成后循环刚好结束,若写成:

	while (*destination && *source)
	{
		*destination++ = *source++;
	}

在循环结束时还需要额外进行一次'\0'的拷贝。

3. 模拟strcmp

(1)实现思路:对两个字符串中的字符逐个进行对比,按规定返回对比结果,即:
第一个字符串大于第二个字符串,则返回大于0的数字
第一个字符串等于第二个字符串,则返回0
第一个字符串小于第二个字符串,则返回小于0的数字
(2)实现代码

int sim_strcmp(const char* s1, const char* s2)
{
	assert(s1 && s2);

	while (*s1 == *s2 && *s1 != '\0' && *s2 != '\0')
	{
		s1++;
		s2++;
	}
	return *s1 - *s2;
}

说明

  • 若两字符串中有任一字符串"\0",则不进行循环,直接返回两字符串中当前字符相减的结果(大于0的数字或小于0的数字);
  • 若不是上述情况,则逐字符进行对比,相等则跳过,直到不同的字符,返回两字符串中当前字符相减的结果(大于0的数字或小于0的数字);
  • 若直到末尾’\0’处都没有不同的字符,说明两字符串相同,也可以直接返回两字符串中当前字符相减的结果(为0)

补充:也可以将返回的小于零的数字具体为-1;将大于零的数字具体为1
如下VS编译器中strcmp的源码

int __cdecl strcmp (
        const char * src,
        const char * dst
        )
{
        int ret = 0 ;

        while((ret = *(unsigned char *)src - *(unsigned char *)dst) == 0 && *dst)
                {
                ++src, ++dst;
                }

        return ((-ret) < 0) - (ret < 0); // (if positive) - (if negative) generates branchless code
}

最后的返回语句通过两个逻辑表达式的结果做差,实现了将返回值具体化。

4. 模拟strcat

(1)实现思路:先在目标字符串(destination)中找到追加的位置,即目标字符串结尾’\0’处,然后从’\0’开始进行字符串的追加即可。
(2)实现代码如下,请看:

char* sim_strcat(char* destination, const char* source)
{
	//1. 找到目标空间的\0
	//注意这里就不能把*destination++直接作为循环条件,会跳过一个\0
	char* ret = destination;
	while (*destination)
	{
		destination++;
	}

	//2. 追加字符串
	while (*destination++ = *source++)
	{
		;
	}
	return ret;
}

补充:上面在介绍strcat函数的时候说过,若想实现对自身的拷贝,不能使用这个函数。因为由模拟实现的过程可以看出,我们是从目标字符串中'\0'的位置开始进行追加的,若目标字符串与源字符串是同一个字符串,那么在追加的时候'\0'被覆盖了,也就是说,追加的字符串(源字符串)中已经没有字符串结束标志'\0'了,此时若进行追加将可能造成程序的死循环
示意图参考:
在这里插入图片描述

5. 模拟strstr

(1)实现思路:从子串的第一个字符与主串的第一个字符进行对比,若相同,则进行下一个字符的对比,直至子串到达'\0',表示匹配成功;若不同,子串退回到第一个字符,从主串的下一个字符开始与主串进行对比;若直至主串到达'\0'都没有匹配成功,则返回一个空指针。
(PS:这里采用的是BF算法,可用KMP算法进行优化,后面会再单独写一篇对其进行介绍)
参考示意图:

  • 假设子串为abb,主串为aabcabbca
    第一趟
    在这里插入图片描述
    子串第二个字符与主串不匹配,子串退回到第一个字符,从主串的下一个字符与主串进行对比,
    第二趟对比表现在图中就是:
    在这里插入图片描述
    子串的第三个字符与主串不匹配,子串退回到第一个字符,从主串的下一个字符与主串进行对比,之后的每一趟就都是这个过程:
    第三趟
    在这里插入图片描述
    第四趟
    在这里插入图片描述
    第五趟
    在这里插入图片描述
    匹配成功,返回子串在主串中的位置,也就是该位置首字符的地址,在上图中返回的就是字符串"abbca"首字符的地址
    (2)实现代码,请看:
//BF匹配
char* sim_strstr(const char* s1, const char* s2)
{
	assert(s1 && s2);

	if (*s2 == '\0')	//子串为\0
	{
		return (char*)s1;
	}

	const char* p1 = s1;
	const char* p2 = s2;
	const char* start = s1;		//用于记录开始比较的位置
	while (*p1)
	{									//以防主串可能小于子串,循环条件不能只为*p1 == *p2
		while (*p1 == *p2 && *p1 != '\0' && *p2 != '\0')	//单字符匹配成功则匹配下一个字符
		{
			p1++;
			p2++;
		}//跳出这层循环只有如下两种可能:

		if (*p2 == '\0')	//匹配成功,返回开始比较的位置
			return (char*)start;
							//单趟匹配失败,子串退回到第一个字符,进行从主串的下一个字符开始与主串匹配
		p1 = start + 1;
		start = p1;
		p2 = s2;
	}
	return NULL;		//跳出外层循环说明匹配失败
}

6. 模拟memcpy

这里先对第一部分的介绍做一个补充,由第一部分的介绍,我们知道函数声明为:

void * memcpy ( void * destination, const void * source, size_t num );

说明:因为我们不确定将来要用函数来处理什么样类型的数据,所以将该函数参数设计为了void*型,用以接收不同类型的数据。最后一个参数num则是实现数据拷贝的关键,因为这里涉及到关于char* 类型指针的妙用。
(PS:关于这部分知识点的详细介绍感兴趣的朋友们可以参考一下博主的这篇文章:【逐步剖C】-第八章-指针进阶-上,在文章的最后讲解模拟实现qsort库函数时进行了较详细的讲解,这里就不再做过多说明啦)
(1)实现思路
将数据转换为char*型,然后再根据第三个参数num就能够借助循环来实现逐字节地进行内容的拷贝
(2)实现代码如下,请看

void* memcpy(void* dest, const void* src, size_t nums)
{
	int i = 0;
	for (i = 0; i < nums; i++)
	{
		*((char*)dest + i) = *((char*)src + i);
	}
	return (char*)dest;
}

7. 模拟memmove

前言:由第一部分的介绍我们知道,用memcpy函数拷贝自身内容的行为是未定义的。即可能会造成错误。
例如:数组arr的中的内容为1 2 3 4 5 6 7 8 9 10;当想将1 2 3 4 5(源空间)拷贝到3 4 5 6 7(目标空间)的位置上时:

  • 1拷贝到3的位置,没问题;
  • 2拷贝到4的位置,没问题;
  • 想将3拷贝到5的位置时就出现问题了,因为数组中原来的3因为前面的拷贝而被覆盖了。
    出现问题的原因是:memcpy所实现的拷贝都是 “从前向后” 的拷贝(即从源空间第一个位置开始覆盖目标空间对应第一个开始的内容);而如上例子若想正确拷贝需要 “从后向前” 拷贝(即从源空间最后一个位置开始覆盖目标空间对应最后一个开始的内容),即拷贝的过程应为:
  • 5拷贝到7的位置,没问题;
  • 4拷贝到6的位置,没问题;
  • 3拷贝到5的位置,没问题;
  • 2拷贝到4的位置,没问题;
  • 1拷贝到3的位置,没问题;
  • 拷贝完成,最终结果为:1 2 1 2 3 4 5 8 9 10

memmove函数与memcpy函数的区别就在于:memmove函数会根据函数的拷贝情况决定是 “从前向后” 拷贝,还是 “从后向前” 拷贝;而memcpy函数只能实现 “从前向后” 拷贝。

memmove函数决定拷贝方式的标准为

  • 目标空间的地址小于源空间的地址时,采用的是 “从前向后” 拷贝的方式。
    示意图参考:
    在这里插入图片描述
    3拷贝到1的位置,4拷贝到2的位置…以此类推。

  • 目标空间的地址大于源空间的地址时,采用的是 “从后向前” 拷贝的方式。
    示意图参考:
    在这里插入图片描述
    5拷贝到7的位置,4拷贝到6的位置…以此类推。

(1)实现思路:由上面介绍可知,“从前向后” 拷贝的过程其实就和memcpy函数一模一样;那么“从后向前” 拷贝本质上就只是对循环的改变,即让循环从最后一个字节开始往第一个字节拷贝内容
(2)实现代码如下,请看

void* memmove(void* dest, const void* src, size_t nums)
{
	//本质上分两种情况
	int i = 0;

	if (dest < src)	//从前向后
	{
		for (i = 0; i < nums; i++)
		{
			*((char*)dest + i) = *((char*)src + i);
		}
	}
	else					//从后向前
	{
		for (i = nums - 1 ; i >= 0; i--)	
		{
			*((char*)dest + i) = *((char*)src + i);
		}
		//要换20个字节,但注意是从nums-1开始,到最后i=0时进行最后一次拷贝
	}
	return (char*)dest;
}

本章完。

看完觉得有觉得帮助的话不妨点赞收藏鼓励一下,有疑问或有误地方的地方还恳请过路的朋友们留个评论,多多指点,谢谢朋友们!🌹🌹🌹

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

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

相关文章

C语言-基础了解-11-C作用域规则

C作用域规则 一、C作用域规则 任何一种编程中&#xff0c;作用域是程序中定义的变量所存在的区域&#xff0c;超过该区域变量就不能被访问。C 语言中有三个地方可以声明变量&#xff1a; 1、在函数或块内部的局部变量 2、在所有函数外部的全局变量 3、在形式参数的函数参数定…

Oracle Primavera P6 学习地图(Updating)

目录P6介绍及使用P6异常处理P6部署配置维护P6集成及开发P6集成及开发为了方便大家更好的针对查询我博客中的内容&#xff0c;特针对P6不同方面进行简要分类&#xff0c;如在使用P6过程中有碰到任何问题&#xff0c;欢迎通过如下方式与我取得联系(查询联系方式) P6介绍及使用 P…

什么是EventLoop?怎么测试Node或页面的性能

Event Loop 机制大家应该都有了解。本文利用 EventLoop 去做一个有趣的检测node或页面性能的代码&#xff0c;顺便介绍了一下EventLoop&#xff0c;希望对大家有所帮助&#xff01; Event Loop Event Loop 机制大家应该都有了解。我先重复总结一下。 Node.js 和 Javascript 的…

1.6 独立性

1.6.1 事件的独立性1.两个事件的独立性中任意两个事件都相互独立、則称 A,.A.&#xff0c;,A.两两独立&#xff0c;显然•若&#xff0c;个事件相互独立,則一定两两独立,反之,不一定成立【例 1.251 将一个均匀的正四面体的第一面染上红、黄、蓝三色&#xff0c;将其他三百多别染…

C语言实现扫雷【详细讲解+全部源码】

扫雷的实现1. 配置运行环境2. 扫雷游戏的初步实现2.1 建立扫雷分布模块2.2 创建名为board的二维数组并进行棋盘初始化2.3 打印棋盘3. 接下来该讨论的事情3.1 布置雷3.2 排查雷3.3 统计坐标周围有几个雷4. 完整扫雷游戏的实现4.1 game.h4.2 game.c4.3 扫雷.c1. 配置运行环境 本游…

你相信吗?用ChatGPT写井字棋游戏仅需几分钟

井字棋 我们先实现一个最基本的使用控制台交互的井字棋游戏。 为了保持代码整洁&#xff0c;方便后续扩展&#xff0c;我们使用类Board来实现棋盘。除了常规的初始化方法__init__和字符串方法__str__&#xff0c;我们还要判断游戏的胜负、棋子位置的合理性。 在main中&…

扩展WSL2虚拟硬盘的大小

扩展WSL2虚拟硬盘的大小 1、在 Windows PowerShell 中终止所有 WSL 实例 wsl --shutdown2、查看 WSL 实例运行状态&#xff0c;确认关闭&#xff0c;并记住发行版的名称 wsl -l -v如果没有更改移动过发行版安装包位置&#xff0c;那么可以通过以下方法查找到发行版的安装包位…

[算法]选择排序

目录 1、选择排序的实现 2、例子 3、代码实现 4、时间复杂度和空间复杂度 5、选择排序的缺点——不稳定性 1、选择排序的实现 选择排序就是每一轮选择最小的元素直接交换到左侧。这种排序的最大优势&#xff0c;就是省去了多余的元素交换。 2、例子 原始数组和选择排序的…

NSIS 多语言安装界面

NSIS默认的打包界面多语言不太好用&#xff0c;因为界面不能跟着切换语言上面的文字也随着切换&#xff0c;所以只能是考虑自定义的方法解决这个问题 本人采用duilib与NSIS结合的方法&#xff0c;效果如下所示&#xff1a; ;获取系统默认的语言 System::Call Kernel32::Ge…

仪表放大器放大倍数分析-运算放大器

仪表放大器是一种非常特殊的精密差分电压放大器&#xff0c;它的主要特点是采用差分输入、具有很高的输入阻抗和共模抑制比&#xff0c;能够有效放大在共模电压干扰下的信号。本文简单分析一下三运放仪表放大器的放大倍数。 一、放大倍数理论分析 三运放仪表放大器的电路结构…

如何快速在企业网盘中找到想要的文件

现在越来越多的企业采用企业网盘来存储文档和资料&#xff0c;而且现在市面上的企业网盘各种各样。在使用企业网盘过程中&#xff0c;很多用户会问到企业网盘中如何快速搜索文件的问题。但是无论是“标签”功能还是普通的“关键词搜索”功能&#xff0c;都是单层级的&#xff0…

SAP MM学习笔记7-SAP标准功能和Add-on之间的关系

大家都知道SAP标准功能异常强大&#xff0c;而且也可以用ABAP做Add-on开发&#xff0c;在ERP市场长期占No1地位&#xff0c;那么SAP标准功能和Add-on之间到底有什么的关系呢&#xff1f; 咱们今天就来探讨一下。 1,一图说明标准和Add-on之间的关系 <图中上面一行> 1&am…

Javalin解构

Javalin Javalin是一个轻量级http框架&#xff0c;我们可以很容易的了解请求的处理过程及其设计&#xff0c;具有较高的学习意义。 从demo说起 public static void main(String[] args) {Javalin app Javalin.create(config -> {System.out.println("用户配置"…

Java——N叉树的层序遍历

题目链接 leetcode在线oj题——N叉树的层序遍历 题目描述 给定一个 N 叉树&#xff0c;返回其节点值的层序遍历。&#xff08;即从左到右&#xff0c;逐层遍历&#xff09;。 树的序列化输入是用层序遍历&#xff0c;每组子节点都由 null 值分隔&#xff08;参见示例&…

网络基础(三)

目录 网络层与数据链路层 ​编辑 网络层 IP协议 IP的构成 TCP和IP各自解决什么问题&#xff1f; 基本概念 协议头格式 协议头分析 如何分离与封装&#xff1f; 如何分用(向上交付)&#xff1f; 16位首部校验和 32位源IP和目的IP 4位版本 8位服务类型(Type Of…

【计算机】单位制前缀的歧义-KB、kb、MB混用

引言 经常遇到容量、带宽的单位&#xff0c;MB&#xff0c;GB在进行单位换算时&#xff0c;总是傻傻分不清&#xff0c;查些资料浅记录一下。 公制&#xff08;metric system&#xff09; 又译米制&#xff0c;是一个国际化十进位量度系统。法国在1799年开始使用公制&#xf…

【微信小程序】-- 页面导航 -- 声明式导航(二十二)

&#x1f48c; 所属专栏&#xff1a;【微信小程序开发教程】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &…

maven生命周期、阶段与默认绑定插件梳理

maven生命周期、阶段与默认绑定插件梳理 CSDN博客 码云源码 1.maven生命周期、阶段与默认绑定插件 序号生命周期lifecycle阶段phase默认绑定插件(链接官网)默认绑定插件(链接maven库)说明1cleancleanmaven-clean-pluginmaven-clean-plugin清理2.1buildvalidate——验证2.2b…

Unity记录1.1-入门-下载与创建项目

文章首发及后续更新&#xff1a;https://mwhls.top/4439.html&#xff0c;无图/无目录/格式错误/更多相关请至首发页查看。 新的更新内容请到mwhls.top查看。 欢迎提出任何疑问及批评&#xff0c;非常感谢&#xff01; 汇总&#xff1a;Unity 记录 写的很简略&#xff0c;因为不…

【数据挖掘与商务智能决策】第一章 数据分析与三重工具

numpy基础 numpy与数组 import numpy as np # 用np代替numpy,让代码更简洁 a [1, 2, 3, 4] # 创建列表a b np.array([1, 2, 3, 4]) #从列表ach print(a) print(b) print(type(a)) #打印a类型 print(type(b)) #打印b类型[1, 2, 3, 4] [1 2 3 4] <class ‘list’>…