C语言-字符串+内存函数介绍与模拟实现(10)

news2024/11/24 8:45:40

目录

思维导图:

字符串与内存函数

求字符串长度

strlen

长度不受限制的字符串函数

strcpy

strcat

strcmp

长度受限制的字符串函数介绍

strncpy

strncat

strncmp

字符串查找

strstr

strtok

错误信息报告

strerror

perror

字符操作

内存操作函数

memcpy

memmove

memset

memcmp

写在最后:


思维导图:

字符串与内存函数

求字符串长度

strlen

size_t strlen ( const char * str )

其实我们对于strlen函数并不陌生,

他能通过字符串首地址求出字符串长度。

既然如此,我们来挑战一下,用三种不同的方法实现strlen函数:

第一种:循环

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

//size_t strlen(const char * str)
size_t my_strlen(const char* str)
{
	assert(str);
	int count = 0;//计数
	while (*str)//遍历数组
	{
		str++;
		count++;
	}
	return count;
}

int main()
{
	char arr[] = "abcdef";
	int len = my_strlen(arr);
	printf("%d\n", len);
	return 0;
}

输出:

输出:6

第二种:递归

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

//size_t strlen(const char * str)
size_t my_strlen(const char* str)
{
	assert(str);
	if (*str != '\0')
		return 1 + my_strlen(str + 1);
	else
		return 0;
}

int main()
{
	char arr[] = "abcdef";
	int len = my_strlen(arr);
	printf("%d\n", len);
	return 0;
}

输出:

输出:6

第三种:指针减指针

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

//size_t strlen(const char * str)
size_t my_strlen(const char* str)
{
	assert(str);
	const char* start = str;
	while (*str)
	{
		str++;
	}
	return str - start;//指针之间隔着一整个数组
	//数组在内存中是连续存储的,start与str之间相差6个字节
}

int main()
{
	char arr[] = "abcdef";
	int len = my_strlen(arr);
	printf("%d\n", len);
	return 0;
}

输出:

输出:6

怎么样,学会了吗?

长度不受限制的字符串函数

strcpy

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

strcpy是字符串拷贝函数,可以拷贝字符串

例:

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

int main()
{
	char arr1[] = "welcome to my blog";
	char arr2[30] = { 0 };
	strcpy(arr2, arr1);
	printf("%s\n", arr2);
	return 0;
}

输出:

输出:welcome to my blog

注:

1.源字符串必须以 '\0' 结束,

2.该函数会将源字符串中的 '\0' 拷贝到目标空间,

3.目标空间必须足够大,以确保能存放源字符串。

接下来我们可以模拟实现一下strcpy函数:

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

//char* strcpy(char* destination, const char* source)
char* my_strcpy(char* dest, const char* src)
{
	assert(dest && src);
	char* ret = dest;
	while (*dest++ = *src++)
	{
		;
	}
	return ret;//返回的是目标字符串的首字符地址
}

int main()
{
	char arr1[] = "welcome to my blog";
	char arr2[30] = { 0 };
	my_strcpy(arr2, arr1);
	printf("%s\n", arr2);
	return 0;
}

输出:

输出:welcome to my blog

strcat

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

strcat是个字符串追加函数,可以追加字符串。

例:

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

int main()
{
	char arr1[30] = "welcome to";
	char arr2[] = " my ";
	strcat(arr1, arr2);
	strcat(arr1, "blog");
	printf("%s\n", arr1);
	return 0;
}

输出:

输出:welcome to my blog

注:

1.源字符串必须以 '\0' 结束,

2.目标空间必须有足够的大,能容纳下源字符串的内容,

3.目标空间必须可修改。

接下来我们可以模拟实现一下strcat函数:

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

//char* strcat(char* destination, const char* source)
char* my_strcat(char* dest, const char* src)
{
	assert(dest && src);
	const char* ret = dest;
	while (*dest)//指针到'\0'停下
	{
		dest++;
	}
	while (*dest++ = *src++)
	{
		;
	}
	return ret;
}

int main()
{
	char arr1[30] = "welcome to";
	char arr2[] = " my ";
	my_strcat(arr1, arr2);
	my_strcat(arr1, "blog");
	printf("%s\n", arr1);
	return 0;
}

输出:

输出:welcome to my blog

strcmp

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

strcmp是字符串比较函数,可以用来进行字符串之间的比较。

例:

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

int main()
{
	char arr1[] = "abcd";
	char arr2[] = "abcz";
	int ret = strcmp(arr1, arr2);//按照字典序来排
	if (ret > 0)
		printf("arr1>arr2\n");
	else if (ret == 0)
		printf("arr1=arr2\n");
	else
		printf("arr1<arr2\n");
	return 0;
}

输出:

输出:arr1<arr2

注:

1.第一个字符串大于第二个字符串,则返回大于0的数字,

2.第一个字符串等于第二个字符串,则返回0,

3.第一个字符串小于第二个字符串,则返回小于0的数字。

接下来我们可以模拟实现一下strcmp函数:

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

int my_strcmp(const char* src, const char* dest)
{
    int ret = 0;
    assert(src &&dest);
	while (!(ret = *(unsigned char*)src++ - *(unsigned char*)dest++) && *dest && *src)
	{     //!ret如果ret!=0则跳出循环,ret=0则继续,*dest=0和*src=0也跳出循环
		;
	}
	if (ret < 0)
		ret = -1;
	else if (ret > 0)
        ret = 1;
    return ret;
}

int main()
{
	char arr1[] = "abcd";
	char arr2[] = "abcz";
	int ret = my_strcmp(arr1, arr2);//按照字典序来排
	if (ret > 0)
		printf("arr1>arr2\n");
	else if (ret == 0)
		printf("arr1=arr2\n");
	else
		printf("arr1<arr2\n");
	return 0;
}

输出:

输出:arr1<arr2

以上就是长度不受限制的字符串函数。

长度受限制的字符串函数介绍

strncpy

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

strncpy可以控制拷贝过去的字符串的字符个数。

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

int main()
{
	char arr1[20] = "xxxxxxxxxxxxx";
	char arr2[] = "hello";
	strncpy(arr1, arr2, 3);
	printf("%s\n", arr1);
	strncpy(arr1, arr2, 6);//\0也会被拷贝过去
	printf("%s\n", arr1);
	return 0;
}

输出:

输出:
helxxxxxxxxxx
hello

他的实现方式与strcpy自然也是大同小异。

例:

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

//char* strncpy(char* destination, const char* source, size_t num)
char* my_strncpy(char* dest, const char* src, size_t num)
{
	assert(dest && src);
	char* ret = dest;
	for (int i = 0; i < num; i++)
	{
		*dest++ = *src++;
	}
	return ret;//返回的是目标字符串的首字符地址
}

int main()
{
	char arr1[20] = "xxxxxxxxxxxxx";
	char arr2[] = "hello";
	my_strncpy(arr1, arr2, 3);
	printf("%s\n", arr1);
	my_strncpy(arr1, arr2, 6);//\0也会被拷贝过去
	printf("%s\n", arr1);
	return 0;
}

输出:

输出:
helxxxxxxxxxx
hello

strncat

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

strncat可以控制追加字符的数量。

例:

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

int main()
{
	char arr1[30] = "welcome to";
	char arr2[] = " my ";
	strncat(arr1, arr2, 2);
	strncat(arr1, "blog", 2);
	printf("%s\n", arr1);
	return 0;
}

输出:

输出:welcome to mbl

我们也能将它模拟实现一下:

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

//char* strncat(char* destination, const char* source, size_t num)
char* my_strncat(char* dest, const char* src, size_t num)
{
	assert(dest && src);
	const char* ret = dest;
	while (*dest)//指针到'\0'停下
	{
		dest++;
	}
	for (int i = 0; i < num; i++)
	{
		*dest++ = *src++;
	}
	return ret;
}

int main()
{
	char arr1[30] = "welcome to";
	char arr2[] = " my ";
	my_strncat(arr1, arr2, 2);
	my_strncat(arr1, "blog", 2);
	printf("%s\n", arr1);
	return 0;
}

输出:

输出:welcome to mbl

strncmp

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

strncmp可以控制比较的字符串的字符数。

例:

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

void print(int ret)
{
	if (ret > 0)
		printf("arr1>arr2\n");
	else if (ret == 0)
		printf("arr1=arr2\n");
	else
		printf("arr1<arr2\n");
}

int main()
{
	char arr1[] = "abcd";
	char arr2[] = "abcz";
	int ret = strncmp(arr1, arr2, 3);
	print(ret);
	ret = strncmp(arr1, arr2, 4);
	print(ret);
	return 0;
}

输出:

输出:
arr1=arr2
arr1<arr2

字符串查找

strstr

strstr函数可以查找字符串中的字符,并返回他们的地址。

如果找不到对应字符或字符串,就返回空指针。

例:

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

int main()
{
	char arr[] = "welcome to my blog";
	char* p = strstr(arr, "my");
	printf("%s\n", p);
	return 0;
}

输出:

输出:my blog

例2:

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

int main()
{
	char arr1[] = "abbbcdbbcef";
	char arr2[] = "bbcb";
	char* ret = strstr(arr1, arr2);
	if (ret == NULL)
	{
		printf("找不到\n");
	}
	else
	{
		printf("%s\n", ret);
	}
	return 0;
}

输出:

输出:找不到

接下来我们可以模拟实现一下strstr函数:


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

//char* strstr(const char* str1, const char* str2)
char* my_strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);
	if (*str2 == '\0')
	{
		return (char*)str1;
	}
	const char* s1 = NULL;
	const char* s2 = NULL;//初始化指针
	const char* cp = str1;//cp指针的作用是作为遍历字符串str1的起始地址

	while (*cp)//如果*cp已经等于'\0'了就证明查找失败了,不再进入循环
	{
		s1 = cp;//如果没找到,s1指针返回cp地址,也就是遍历开始的地址
		s2 = str2;//而s2指针返回str2的地址,重新对应查找
		while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2)//匹配
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
		{
			return (char*)cp;
		}
		cp++;//没找到,遍历的地址向前一个字节
	}
	return NULL;
}

int main()
{
	char arr1[] = "abbbcdbbcef";
	char arr2[] = "bbc";
	char* ret = my_strstr(arr1, arr2);
	if (ret == NULL)
	{
		printf("找不到\n");
	}
	else
	{
		printf("%s\n", ret);
	}
	return 0;
}

输出:

输出:bbcdbbcef

strtok

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

strtok函数可以通过分隔符sep分割字符串,并标记

如果之后传空指针,也能通过标记继续分割字符串。

例:

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

int main()
{
	char arr[] = "asdf@hjkl.qwer";
	char* p = "@.";
	char buf[20] = { 0 };
	strcpy(buf, arr);

	char* pa = strtok(buf, p);
	printf("%s\n", pa);

	pa = strtok(NULL, p);//传空指针
	printf("%s\n", pa);

	pa = strtok(NULL, p);
	printf("%s\n", pa);

	return 0;
}

输出:

输出:
asdf
hjkl
qwer

但是,我们发现,想上面那样写的话,

代码有一点冗余了,该怎么解决呢?

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

int main()
{
	char arr[] = "asdf@hjkl.qwer";
	char* p = "@.";
	char buf[20] = { 0 };
	strcpy(buf, arr);
	char* ret = NULL;
	for (ret = strtok(buf, p); ret != NULL; ret = strtok(NULL, p))
	{
		printf("%s\n", ret);
	}
	return 0;
}

输出:

输出:
asdf
hjkl
qwer

写成循环的形式就好多啦。

错误信息报告

strerror

C语言的库函数在运行的时候,如果发生错误,

就会将错误码存在一个变量中,这个变量是:errno。

而strerror 函数能将错误码翻译成错误信息。

例:

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

int main()
{
	//错误码是一些数字:1 2 3 4 5 ,他们都有不同的含义
	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;
}

输出:

输出:
No error
Operation not permitted
No such file or directory
No such process
Interrupted function call
Input/output error


perror

但在平时,perror用的也很多,

举个例子:

#include <stdio.h>
#include <string.h>
#include <errno.h>//这个是errno的头文件

int main()
{
	//打开文件
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));//实际上我们并没有这个文件,就能通过strerror报错
		return 1;
	}
	//读文件
	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

输出:

输出:No such file or directory

但是使用perror 函数会更方便和灵活。

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

int main()
{
	//打开文件
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读文件
	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

输出:

输出:fopen: No such file or directory

字符操作

字符分类函数:

函数如果他的参数符合下列条件就返回真
iscntrl任何控制字符
isspace空白字符:空格‘ ’,换页‘\f’,换行'\n',回车‘\r’,制表符'\t'或者垂直制表符'\v'
isdigit十进制数字 0~9
isxdigit十六进制数字,包括所有十进制数字,小写字母a~f,大写字母A~F
islower小写字母a~z
isupper大写字母A~Z
isalpha字母a~z或A~Z
isalnum字母或者数字,a~z,A~Z,0~9
ispunct标点符号,任何不属于数字或者字母的图形字符(可打印)
isgraph任何图形字符
isprint任何可打印字符,包括图形字符和空白字符

例:

#include <stdio.h>
#include <ctype.h>

int main()
{
	int ret = isdigit('Q');//参数是十进制数字 0~9返回真,否则返回假
	printf("%d\n", ret);

	return 0;
}

输出:

输出:0

还有一些字符操作函数:

例:

#include <stdio.h>
#include <ctype.h>

int main()
{
	printf("%c\n", toupper('a'));//转成大写
	printf("%c\n", tolower('A'));//转成小写

	return 0;
}

输出:

输出:
A
a

内存操作函数

memcpy

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

memcpy是内存拷贝函数:

1.函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。

2.这个函数在遇到 '\0' 的时候并不会停下来。

3.如果source和destination有任何的重叠,复制的结果都是未定义的(会出问题)。

例:

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

void print(int* arr, int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}

int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };
	memcpy(arr2, arr1 + 2, 17);//17个字节
	int sz = sizeof(arr2) / sizeof(arr2[0]);
	print(arr2, sz);
}

输出:

输出;3 4 5 6 7 0 0 0 0 0

接下来我们可以模拟实现一下memcpy函数:

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

void print(int* arr, int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}

//void* memcpy(void* destination, const void* source, size_t num)
void* my_memcpy(void* dest, const void* src, size_t num)
{
	assert(dest && src);
	void* ret = dest;//记住起始地址
	while (num--)
	{
		*(char*)dest = *(char*)src;//一个字节一个字节的拷贝
		++(char*)dest;
		++(char*)src;
	}
	return ret;
}

int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };
	my_memcpy(arr2, arr1 + 2, 17);//17个字节
	int sz = sizeof(arr2) / sizeof(arr2[0]);
	print(arr2, sz);
}

输出:

输出:3 4 5 6 7 0 0 0 0 0

memmove

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

memmove函数的功能与memcpy的功能类似,但也有差别:

1.和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。

2.如果源空间和目标空间出现重叠,就得使用memmove函数处理

例:

如果使用memcpy,拷贝的结果就会出问题:

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

void print(int* arr, int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}

//void* memcpy(void* destination, const void* source, size_t num)
void* my_memcpy(void* dest, const void* src, size_t num)
{
	assert(dest && src);
	void* ret = dest;//记住起始地址
	while (num--)
	{
		*(char*)dest = *(char*)src;//一个字节一个字节的拷贝
		++(char*)dest;
		++(char*)src;
	}
	return ret;
}

int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memcpy(arr1 + 2, arr1, 17);//17个字节
	int sz = sizeof(arr1) / sizeof(arr1[0]);
	print(arr1, sz);
}

输出:

输出:1 2 1 2 1 2 1 8 9 10

我们想要的结果是:1 2 1 2 3 4 5 8 9 10

(注:在VS2019的环境下,memcpy的库函数实现已经和memmove一样了)

那就得使用memmove函数:

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

void print(int* arr, int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}

int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	memmove(arr1 + 2, arr1, 17);//17个字节
	int sz = sizeof(arr1) / sizeof(arr1[0]);
	print(arr1, sz);
}

输出:

输出:1 2 1 2 3 4 5 8 9 10

这样就成功得到我们想要的值了。

接下来我们可以模拟实现一下memmove函数:

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

void print(int* arr, int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}

//void* memmove(void* destination, const void* source, size_t num)
void* my_memmove(void* dest, const void* src, size_t num)
{
	assert(dest && src);
	void* ret = dest;
	if (dest < src)//通过判断避免数组内容覆盖导致的错误
	{
		//从前往后拷贝数组内容
		while (num--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	else
	{
		//从后往前拷贝数组内容
		while (num--)
		{
			*((char*)dest + num) = *((char*)src + num);
		}
	}
}

int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memmove(arr1 + 2, arr1, 17);//17个字节
	int sz = sizeof(arr1) / sizeof(arr1[0]);
	print(arr1, sz);
}

输出:

输出:1 2 1 2 3 4 5 8 9 10

memset

void * memset ( void * ptr, int value, size_t num )

memset是内存定义函数,我们一般用它来进行初始化操作。

例:

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

void print(int* arr, int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
}

int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	memset(arr1, 0, sizeof(arr1));//设置成0
	char arr2[20] = "hello world";
	memset(arr2, 'x', 5);//把五个字节的内容设置成‘x’
	int sz = sizeof(arr1) / sizeof(arr1[0]);
	print(arr1, sz);
	printf("%s\n", arr2);
}

输出:

输出:
0 0 0 0 0 0 0 0 0 0
xxxxx world

memcmp

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

memcmp函数能比较从ptr1和ptr2指针开始的num个字节,

ptr1 > ptr2 返回 >0 的数,

ptr1 < ptr2 返回 <0 的数,

ptr1 = ptr2 返回 =0 的数。

例:

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

int main()
{
	char arr1[] = "abcd";
	char arr2[] = "abcz";
	int ret = memcmp(arr1, arr2, 4);//比较四个字节的内容
	if (ret > 0)
		printf("arr1>arr2\n");
	else if (ret == 0)
		printf("arr1=arr2\n");
	else
		printf("arr1<arr2\n");
	return 0;
}

输出:

输出:arr1<arr2

写在最后:

以上就是本篇文章的内容了,感谢你的阅读。

如果喜欢本文的话,欢迎点赞和评论,写下你的见解。

如果想和我一起学习编程,不妨点个关注,我们一起学习,一同成长。

之后我还会输出更多高质量内容,欢迎收看。

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

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

相关文章

Linux之select、poll、epoll讲解

文章目录1 select、poll、epoll1.1 引言1.2 IO和Linux内核发展1.2.1 整体概述1.2.2 阻塞IO1.2.3 非阻塞IO1.2.4 select1.2.5 共享空间1.2.6 零拷贝1.3 select1.3.1 简介1.3.2 select缺点1.4 poll介绍1.4.1 与select差别1.4.2 poll缺点1.5 epoll1.5.1 epoll相关函数1.5.2 epoll优…

详解floor函数、ceil函数和round函数

1.floor函数 功能&#xff1a;把一个小数向下取整 即就是如果数是2.2 &#xff0c;那向下取整的结果就为2.000000 原型&#xff1a;double floor(doube x); 参数解释&#xff1a; x:是需要计算的数 返回值&#xff1a; 成功&#xff1a;返回一个double类型的数&#xff0c;此数…

6-星际密码

题目 星际战争开展了100年之后&#xff0c;NowCoder终于破译了外星人的密码&#xff01;他们的密码是一串整数&#xff0c;通过一张表里的信息映射成最终4位密码。表的规则是&#xff1a;n对应的值是矩阵X的n次方的左上角&#xff0c;如果这个数不足4位则用0填充&#xff0c;如…

C语言-自定义类型-结构体(11.1)

目录 思维导图&#xff1a; 1.结构体类型的基础知识 1.1结构体的声明 1.2特殊的声明 2.结构的自引用 3.结构体变量的定义和初始化 4.结构体内存对齐 4.1如何计算 4.2如何修改内对齐数 5.结构体传参 写在最后&#xff1a; 思维导图&#xff1a; 1.结构体类型的基础知…

Leetcode:98. 验证二叉搜索树(C++)

目录 问题描述&#xff1a; 实现代码与解析&#xff1a; 递归&#xff1a; 原理思路&#xff1a; 迭代&#xff08;中序&#xff09;&#xff1a; 思路原理&#xff1a; 问题描述&#xff1a; 给你一个二叉树的根节点 root &#xff0c;判断其是否是一个有效的二叉搜索树。…

【目标检测】基于yolov6的钢筋检测和计数(附代码和数据集)

写在前面: 首先感谢兄弟们的订阅,让我有创作的动力,在创作过程我会尽最大能力,保证作品的质量,如果有问题,可以私信我,让我们携手共进,共创辉煌。 Hello,大家好,我是augustqi。 今天给大家分享的目标检测项目是:基于yolov6的钢筋检测和计数实战项目(附代码和数据集…

如何成功发送一个Target 846 EDI报文?

Target塔吉特公司是仅次于沃尔玛的第二大零售百货集团&#xff0c;为客户提供当今时尚前沿的零售服务&#xff0c;物美价廉。而EDI&#xff08;电子数据交换&#xff09;是Target与供应商进行业务往来时要求使用的数据交换方式&#xff0c;具有安全可靠、高效和降低人工成本等优…

磨金石教育摄影技能干货分享|有哪些让你难以忘怀的人文摄影照片

在摄影分类中&#xff0c;人文摄影往往没有明确的释义。它既有纪实摄影的真实&#xff0c;又有艺术摄影的深奥。实际上&#xff0c;人文摄影可以说是二者的结合&#xff0c;在创意和表达上更倾向于艺术性&#xff0c;在画面上更有真实感。1 大雨滂沱这张肖像照极具张力&#xf…

智能家居给我们带来了什么?华秋携手信威安防传感器助力提升家居安全性

智能家居的出现&#xff0c;极大地方便了人们的生活&#xff0c;为生活提供便利舒适的体验&#xff1b;如同洗衣机与洗碗机解放了我们双手一样的道理&#xff0c;智能家居是在生活方方面面为我们了提供最大化的便利可能性。 那么&#xff0c;智能家居是如何为我们生活提供便利…

Jmeter@测试场景

目录 性能测试Jmeter&#xff0c;常用的场景 场景一&#xff1a;Thread Group 场景二、jpgc - Stepping Thread Group 场景三、jpgc - Ultimate Thread Group 场景一&#xff1a;Thread Group 参数配置-线程属性Thread Properties&#xff1a; 1.线程数(Number of Threads)…

并查集的使用

目录 一.介绍 二.并查集的实现 三路径压缩 四.相关题型 4.1省份数量 一.介绍 什么是并查集&#xff1f; 将n个不同的元素划分成一些不相交的集合。开始时&#xff0c;每个元素自成一个 单元素集合&#xff0c;然后按一定的规律将归于同一组元素的集合合并。在这个过程中要…

十五、Express 中使用JWT进行登录验证

cookie 篇 : Node.js 中 cookie的验证登录 | session 篇 : Node.js 中 session验证登录 在前面讲过了两种验证登录的方式&#xff0c;其一是cookie&#xff0c;其二是session&#xff1b;那么在讲JWT之前先来简单的回顾这两种方式区别&#xff1b;cookie和sessi…

成功解决:npm 版本不支持node.js。【 npm v9.1.2 does not support Node.js v16.6.0.】

文章目录1、出现的问题2、查看自己的npm和node版本3、解决方法3.1 寻找对应的版本3.2 升级npm版本4、再次运行项目&#xff0c;成功5、如果上述方法失败&#xff0c;请看这里早起更新代码后&#xff0c;跑前端项目。结果噶了、跑不起来了&#xff1b;不慌&#xff0c;看看日志报…

JiBX 的实操

JiBX 的实操介绍基本概念BECL 介绍JiBX 基础概念开发jar 依赖BECLJiBXPOJO 实体类OrderAddressCustomerShippingOrderFactory 工厂类使用ant 来生成XML和POJO对象的绑定关系idea 使用antant 脚本 build.xmlant 添加 build.xmlbinding.xml报错问题解决测试TestOrder测试结果 如图…

C/C++ STL

常见容器性质总结 1.vector 底层数据结构为数组 &#xff0c;支持快速随机访问 2.list 底层数据结构为双向链表&#xff0c;支持快速增删 3.deque 底层数据结构为一个中央控制器和多个缓冲区&#xff0c;详细见STL源码剖析P146&#xff0c;支持首尾&#xff08;中间 不能&…

java mybatis的SpringBoot博客论坛管理系统

java mybatis的SpringBoot博客论坛管理系统 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java毕设项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言 文末获取源码联系方式…

Java数据结构:堆与PriorityQueue优先级队列的使用

文章目录1 什么是堆2 堆的实现思路2.1 大根堆的成员变量简介2.2 树的相关知识复习2.3 向下调整创建大根堆2.4 堆的插入2.5 堆的删除3 大根堆实现代码及测试4 PriorityQueue的使用4.1 特性简介4.2 常用方法4.3 使用PriorityQueue实现大根堆写在最后1 什么是堆 堆实质上就是对完全…

python对称加密AES的使用

python对称加密AES的使用 aes安装 pip install pycryptodome加密库引用 from Crypto.Util.Padding import pad, unpad from Crypto.Cipher import AES import base64完整代码 from Crypto.Util.Padding import pad, unpad from Crypto.Cipher import AES import base64def A…

带你玩转OpenHarmony AI-基于海思NNIE的AI能力自定义

简介相信大家从玩转OpenAtom OpenHarmony&#xff08;简称“OpenHarmony”&#xff09;AI系列专题的其他文章中&#xff0c;已经拓展了OpenHarmony AI在智慧出行、智慧办公等多场景下的AI自动检测、识别和判断的新体验&#xff0c;对于OpenHarmony平台上的AI开发有了一定认识。…

通过事件总线EventBus/AsyncEventBus进行JAVA模块解耦 (史上最全)

事件总线在 进行JAVA模块解耦 &#xff0c;价值巨大 实际开发中&#xff0c;常常 通过事件总线EventBus/AsyncEventBus进行JAVA模块解耦 &#xff0c; 比如&#xff0c;在顶级开源组件 hotkey的源码中&#xff0c; 就多次用到 EventBus/AsyncEventBus进行JAVA模块解耦 所以&am…