C进阶:字符函数和内存函数

news2025/4/13 18:48:40

字符串函数和内存函数

  • 字符函数和内存函数
    • 字符函数
      • 求字符串长度
        • strlen
      • 长度不受限制的字符串函数
        • strcpy
        • strcat
        • strcmp
      • 长度受限制的字符串函数
        • strncpy
        • strncat
        • strncmp
      • 字符串查找
        • strstr
        • strtok
      • 错误信息报告
        • strerror
      • 字符函数:
    • 内存函数
      • memcpy
      • memmove
      • memcmp
      • memset
  • 库函数的模拟实现
    • 模拟实现strlen
      • 第一种方法:
      • 第二种方法:
      • 第三种方法:
    • 模拟实现strcpy
    • 模拟实现strcat
    • 模拟实现strcmp
    • 模拟实现strstr
    • 模拟实现memcpy
    • 模拟实现memmove

字符函数和内存函数

本节内容重点就是学会使用一些字符函数和内存函数,并且去模拟几个重要的函数,了解和体会这个函数是怎么样去实现的。不知道各位寒假在家学习的怎样,一定要坚持学习啊。好了,话不多说,我们直接开始学习我们的函数吧。

字符函数

求字符串长度

strlen

strlen其实是我们的老朋友了,但是今天我们还是来复习一下它,我们首先来看函数的参数和返回类型,

size_t strlen ( const char * str );

使用strlen需要注意的点:

  • 字符串中一定要有\0,因为字符串是以\0作为结束标志。
  • strlen统计的是字符串中\0之前的字符个数

关于strlen的简单使用就不再举例了。

但是我们还发现一个问题就是,库里面的strlen返回类型实际上是size_t,我们知道size_t其实就是unsigned int(无符号整型),我们可以猜测一下,在函数设计时,设计者可能想的是strlen来求字符串长度,长度大小那么一定为正数,所以设计成了size_t。但是我们在模拟strlen的时候,我们一般将返回类型设为int,这是为什么呢?我们来看下面这样一段代码:

#include <stdio.h>
#include <string.h>
int main()
{
	if (strlen("abc") - strlen("abcdef") > 0)
	{
		printf(">\n");
	}
	else
	{
		printf("<=\n");
	}
	return 0;
}

效果:image-20230111125653304

我猜你想说的一定是-3肯定小于0,打印<=嘛,如果你是这样想的,那么恭喜你,你就错了。实际上我们的结果是输出>,这时候我们就要思考为什么了,实际上还是因为库里面strlen返回值是size_t的问题,两个无符号整型相减得到的一定是无符号整型,将-3的二进制序列看做一个无符号数的话,那值可就大了去了。所以最终结果输出的是>,所以模拟实现strlen的话,返回值设计为int还是size_t没有就绝对的好坏,要根据具体情况来判断。

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

strcpy

字符串拷贝函数,我们先看它的函数参数和返回类型,

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

然后看一下它的信息:

image-20230111121156563

可以看到使用其实就是将source(源头)字符串的地址和destination(目标)字符串的地址传过去,然后它会帮你拷贝,最后返回目标字符串的起始地址。

使用strcpy需要注意的点:

  • 源字符串必须以 ‘\0’ 结束。
  • 会将源字符串中的 ‘\0’ 拷贝到目标空间。
  • 目标空间必须足够大,以确保能存放源字符串。
  • 目标空间必须可变。

使用的一个简单举例:

int main()
{
	char arr1[20] = "xxxxxxxxxxxxxxx";
	char* arr2 = "abcdef";//注意常量字符串不能被修改
	strcpy(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

效果:image-20230111125607715

strcat

首先看函数参数和返回类型,

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

然后看信息:

image-20230111125212763

可以看到实际上strcat和strcpy还是很类似的,都是将目标地址和源头地址传过去,最后将目标字符串起始地址返回。只是效果不同,strcat是在目标字符串的末尾去进行追加。

使用strcat需要注意的点:

  • 源字符串必须以 ‘\0’ 结束。
  • 目标空间必须有足够的大,能容纳下源字符串的内容。
  • 目标空间必须可修改。
  • !!!strcat这函数是不能用来字符串自己给自己追加的

使用简单举例:

//strcat——追加字符串
#include <stdio.h>
#include <string.h>
int main()
{
	char arr1[20] = "hello ";//注意要保证目标空间足够大
	char arr2[] = "world!!";
	strcat(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

效果:image-20230111125716927

到这里看起来一切合情合理,非常顺利,但是其实是有问题的,strcat这函数是不能用来字符串自己给自己追加的,因为我们是从\0开始的,你上来直接把\0结束标志给干掉了,然后后面就会一直追加,程序就停不下来了。

strcmp

先看函数参数和返回类型,字符串比较函数,

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

再看函数信息:

image-20230111132041283

传给strcmp两个字符串的地址,如果第一个字符串小于第二个字符串返回小于0的数字,相等返回0,大于返回大于0的数字。

需要注意的点:

  • 标准规定:
    第一个字符串大于第二个字符串,则返回大于0的数字
    第一个字符串等于第二个字符串,则返回0
    第一个字符串小于第二个字符串,则返回小于0的数字
  • strcmp比较两个字符串是根据第一个不同字符的ASCII码值来比较大小的,千万不要认为是字符串长度。

简单使用举例:

//strcmp——字符串比较
#include <stdio.h>
#include <string.h>
int main()
{
	char* arr1 = "abcdef";
	char* arr2 = "abq";//c小于q
	printf("%d\n",strcmp(arr1, arr2));
	return 0;
}

效果:image-20230111132906577

长度受限制的字符串函数

strncpy

strncpy实际上是同strcpy基本类似,只是最后多了一个函数参数代表个数:

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

需要注意的是:

  • 拷贝num个字符从源字符串到目标空间。
  • 如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。

简单使用举例:

当num小于源字符串长度

//strncpy
#include <stdio.h>
#include <string.h>
int main()
{
	char arr1[] = "xxxxxxxxxx";
	char arr2[] = "abcdef";
	strncpy(arr1, arr2,3);
	printf("%s\n", arr1);
	return 0;
}

效果:image-20230111135822542

当num大于源字符串长度:

//strncpy
#include <stdio.h>
#include <string.h>
int main()
{
	char arr1[] = "xxxxxxxxxx";
	char arr2[] = "abcdef";
	strncpy(arr1, arr2, 7);
	printf("%s\n", arr1);
	return 0;
}

效果:image-20230111135956321

strncat

类似的,strncat也是增加了一个参数代表追加个数:

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

需要注意的点是:当追加完要求的三个时,字符串后面会自动放一个\0。

例如:

//strncat
#include <stdio.h>
#include <string.h>
int main()
{
	char arr1[20] = "hello\0xxxxx";
	char arr2[] = "world!!";
	strncat(arr1, arr2, 3);
	//strncat(arr1, arr2, 7);
	printf("%s\n", arr1);
	return 0;
}

效果:image-20230111141004043

strncmp

同理,strncmp也是比strcmp多了一个函数参数num表示比较前num个字符:

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

简单使用举例:

/*strncmp  example*/
#include <stdio.h>
#include <string.h>
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abcdq";
	printf("%d\n", strncmp(arr1, arr2, 5));
	printf("%d\n", strncmp(arr1, arr2, 4));
	return 0;
}

效果:image-20230111182734869

字符串查找

strstr

先看函数参数和返回值,字符串查找函数。

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

再看函数信息:

image-20230111184353699

传递两个字符串地址,在arr1中查找arr2是否存在,若存在则返回arr1中第一次找到arr2的地址,若没找到则返回空指针。

简单使用举例:

/*strstr  example*/

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

int main()
{
	char* arr1 = "abbcdef";
	char* arr2 = "bbc";
	char* arr3 = "bbcq";
	printf("%s\n", strstr(arr1, arr2));
	printf("%s\n", strstr(arr1, arr3));
	return 0;
}

输出:image-20230111185344987

strtok

这个函数可以说是一个很奇葩的函数,它的作用是将一个字符串分割出来。

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

看函数描述:

image-20230111211204473

还是比较长的,我们来解释一下,就是将一个字符串中的分隔符单独放到一个数组里面,将该数组作为第二个函数参数传给strtok,第一个是想要分割的数组,这样strtok函数能够找到字符串中的分隔符改为\0,将这一部分分割出来,返回这一部分的起始地址。如果没有找到分隔符的话,则返回空指针(NULL)。

需要注意的点:

  • strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。
  • strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。
  • strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
  • strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。如果字符串中不存在更多的标记,则返回 NULL 指针。

简单使用举例:

/*strtok  example*/
#include <stdio.h>
#include <string.h>
int main()
{
	char arr1[] = "lzuobing@handsome.net";
	char* p = "@.";
	char buf[50] = { 0 };
	strcpy(buf, arr1);
	printf("%s\n", strtok(buf, p));
	printf("%s\n", strtok(NULL, p));
	printf("%s\n", strtok(NULL, p));
	printf("%s\n", strtok(NULL, p));
	return 0;
}

输出:image-20230111212059599

但是我们如果每次都这么写确实有点挫,事实上我们通常会巧妙的利用for循环来实现输出,代码如下:

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

int main()
{
	char arr1[] = "lzuobing@handsome.net";
	char* p = "@.";
	char buf[50] = { 0 };
	strcpy(buf, arr1);
	for (char* ret = strtok(buf, p); ret != NULL; ret = strtok(NULL, p))
	{
		printf("%s\n", ret);
	}
	return 0;
}

错误信息报告

strerror

strerror这个函数说实话也是一个比较特别的函数,我们先来看一下函数参数和返回值:

char * strerror ( int errnum );

再看一下函数详细信息:

image-20230112144533602

这个函数就是给它一个错误码作为函数参数,然后返回一个char*的指针,用来翻译成错误信息,

简单使用举例:

#include <stdio.h>
#include <string.h>
//c库函数在使用是出错的话,会返回错误码
//strerror可以将错误码翻译为错误信息
int main()
{
	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;
}

输出:image-20230112145106215

这样我们只是简单举了这样一个例子来解释strerror这个函数,但是在实际情况下不是这样使用的,我们需要用的errno这个宏,

为了实际展示strerror是怎么用的,我们再来简单了解一个函数:文件打开函数fopen,

FILE * fopen ( const char * filename, const char * mode );

image-20230112150441016

这里我们简单看一下即可,fopen函数就是用来打开一个文件,如果打开成功返回一个FILE*的一个指针,如果打开失败则返回一个空指针。

我们来让它打开失败一次用strerror来看一下错误信息:

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

输出:image-20230112151455258

可以看到错误信息是目录中没有文件,因为我们当前目录下是没有test.txt文件的,如果你创建一个再去运行就没有这个报错了。

实际上还有一个函数叫perror,这个函数是能够直接打印出错误信息,而strerror是先将错误码转换为错误信息然后自己去实现打印

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

我们还是上面这个例子,直接用perror来看一下:image-20230112153655574

也是可以的,一个是直接就打印,所以有时候你并不想将错误信息打印出来这个函数就不是特别好了,没有strerror灵活。

字符函数:

这些函数看一下知道即可,有时候用这些函数可能会比较方便,例如判断是否是大写字符或小写字符。

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

内存函数

memcpy

内存拷贝函数,可以拷贝任意类型的内容,先看函数参数和返回类型:

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

再看函数信息:

image-20230112170906048

传递目标地址和源头地址,传递要拷贝的内容大小num个字节,memcpy会帮你把内存拷贝过去最后返回目标起始地址。

简单使用举例:

/*memcpy example*/
#include <stdio.h>
#include <string.h>

int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[5] = { 0 };
	memcpy(arr2, arr1, 20);
	for (int i = 0; i < 5; i++)
	{
		printf("%d ", arr2[i]);
	}
	return 0;
}

memmove

image-20230112184013641

实际上是memcpy一样的功能,和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。 参考下面模拟实现memcpy有详细解释。

memcmp

和strcmp类似,也是一个比较函数,只是通过每一个字节依次比较,

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

image-20230112192856656

1中的内容小于2中的内容,返回小于0的数;相等返回0;大于则返回大于0的数。

简单使用举例:

/*memcmp example*/
#include <stdio.h>
#include <string.h>
int main()
{
	int arr1[] = { 1,2,3 };
	int arr2[] = { 1,2,3 };
	int arr3[] = { 1,2,9 };
	printf("%d\n", memcmp(arr1, arr3,12));
	printf("%d\n", memcmp(arr1, arr2,12));
	printf("%d\n", memcmp(arr3, arr2,12));
	return 0;
}

输出:image-20230112193048180

memset

内存设置函数,先看函数参数和返回值:

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

image-20230112194044052

该函数以字节为单位来将内存中的值来修改为你想要的内容。

简单使用举例:

/*memset example*/
#include <stdio.h>
#include <string.h>
int main()
{
	char arr[] = "hello world!!";
	memset(arr, 'x', 5);
	printf("%s\n", arr);
	return 0;
}

输出:image-20230112194228208

但是这个函数有几个需要注意的点,例如下面情况:

image-20230112194458741

可以看到似乎出问题了,并没有像我们想象的一样全部初始化为1,一定要牢记:memset是以字节为单位进行修改的,我们打开内存看一下你就明白了:

可以看一下内存中的值:image-20230112194721423

每一个字节都是1,当然是一个很大的数字了。

另外还需要注意的是函数第二个参数ASCII码值不能超过255,因为是以字节为单位进行修改的,8个比特位即使是无符号数最大也就255。

通常来说我们一般初始化是用的最多的情况,也就是每一个字节修改成0;

所以使用函数时要注意每一个函数,看使用合不合理。

库函数的模拟实现

模拟实现strlen

我们模拟strlen有三种思路,一是计数器直接计数,二是使用递归的方式,三是指针相减。

第一种方法:

这种方法是最简单的方法,也是最容易理解的方法。

//第一种方法——计数器
#include <assert.h>
int my_strlen(const char* str)
{
	assert(str!=NULL);//判断指针合法性
	int count = 0;//计数器
	while (*str)
	{
		count++; 
		str++;
	}
	return count;
}

第二种方法:

这种递归法如果你是第一次看可能理解不了,可以看之前我写过的这篇文章,里面有详细解释:

(C语言底层逻辑剖析函数篇(其三),函数递归与迭代超详解,斐波那契数列递归经典例题,汉诺塔问题,青蛙跳台阶_比昨天强一点就好的博客-CSDN博客

//第二种方法——递归
#include <assert.h>
int my_strlen(const char* str)
{
	assert(str != NULL);
	if (*str!='\0')
	{
		return 1 + my_strlen(str + 1);
	}
	else
	{
		return 0;
	}
}

第三种方法:

这种方法唯一需要注意的就是理解一下,两指针相减,得到的是中间的元素个数。

//第三种方法——指针相减
#include <assert.h>
int my_strlen(const char* str)
{
	assert(str != NULL);
	const char* start = str;//记录起始地址
	while (*str)
	{
		str++;
	}
	return (int)(str - start);//指针相减得到的是中间元素个数
}

模拟实现strcpy

一个字符一个字符拷贝即可,一直到源头字符串的\0拷贝过去,需要注意的点就是最后要返回目标字符串的起始地址,所以要提前记录一下。

//模拟实现strcpy
#include <assert.h>
char* my_strcpy(char* des, const char* source)
{
	assert(des && source);//判断指针合法性
	char* ret = des;//记录目标字符串起始地址
	while (*des++ = *source++)//拷贝
	{
		;
	}
	return ret;//返回目标起始地址
}

模拟实现strcat

关键是要想清楚要从目标字符串的末尾\0开始追加,一直追加到原字符串的末尾\0。

//模拟实现strcat
#include <assert.h>
char* my_strcat(char* des, const char* source)
{
	assert(des && source);//判断指针合法性
	char* ret = des;//记录起始地址
	//1.找到目标字符串\0
	while (*des)
	{
		des++;
	}
	//2.追加
	while (*des++ = *source++)
	{
		;
	}
	return ret;
}

模拟实现strcmp

按照顺序一个字符一个字符依次比较其ASCII码值即可。

//模拟strcmp
#include <stdio.h>
#include <assert.h>
int my_strcmp(const char* arr1,const char* arr2)
{
    assert(arr1&&arr2);
	while (*arr1==*arr2)
	{
		if (*arr1 == '\0')
		{
			return 0;
		}
		arr1++;
		arr2++;
	}
	/*if (*arr1 < *arr2)
		return -1;
	else
		return 1;*/
	return *arr1 - *arr2;
}

模拟实现strstr

要去模拟这个函数其实不是特别容易,我们需要考虑两种情况:

一种情况较为简单,没有任何重复的元素,直接寻找一遍即可;另一种情况有些复杂,如果中间有重复的元素,则需要用多个指针来实现。

我们可以通过画图来解释:

image-20230111200546714

第一种情况用指针去寻找bbc过程中其实容易出现问题,当我们找到第三个b时,发现不是我们要找的c,但是这时候指针已经往后走了,怎么办,所以这时候我们最后委托两个指针去向后遍历,并且还需要一个指针cp来记录一下开始判断的位置。

//模拟strstr

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

char* my_strstr(const char* str1,const char* str2)
{
	assert(str1 && str2);//判断指针合法性
	if (*str2 == '\0')
	{
		return (char*)str1;//str2为空字符串不做任何处理,直接返回str1
	}
	const char* s1 = str1;//委托两个指针s1,s2
	const char* s2 = str2;
	const char* cp = str1;//记录开始判断的地址
	//重点是理解下面思路
	while (*cp)
	{
		s1 = cp;
		s2 = str2;
		while (*s1 !='\0' && *s2 !='\0' && *s1 == *s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
		{
			return (char*)cp;
		}
		cp++;
	}
	return NULL;
}

模拟实现memcpy

最简单的思路:一个字节一个字节拷贝即可,

#include <assert.h>
void* my_memcpy(void* des, const void* source, int num)
{
	assert(des && source);//判断指针合法性
	void* ret = des;//记录目标起始地址
	while (num--)
	{
		*(char*)des = *(char*)source;
		des = (char*)des + 1;//一定注意这里的写法,不要写成*des++,强制类型转换是临时性的
		source = (char*)source + 1;//
	}
	return ret;
}

我们可以测试一下:image-20230112173014852

当我们这样两组单独的数据去测试的时候看起来没有任何问题,我们再换一种情况,假设我们要将12345拷贝放到34567处,有重复情况时:

看起来似乎就有问题了,并不是我们想要的结果,所以我们上面最简单的思路其实是存在一些问题的。哪里有问题呢,我们来分析一下:

左图是问题分析,右边是解决办法的分情况讨论,

我们这样详细分析清楚之后,实际上真正想要引出的是memmove这个函数,因为memmove实际上就是解决了这个重叠的问题。

模拟实现memmove

我们可以根据以上分析的思路来实现memmove:

//模拟实现memmove
#include <assert.h>

void* my_memmove(char* des, const char* source, size_t num)
{
	assert(des && source);
	char* ret = des;
	if (des < source)
	{
		//前-->后
		while (num--)
		{
			*((char*)des) = *((char*)source);
			des = (char*)des + 1;
			source = (char*)source + 1;
		}
	}
	else
	{
		//后-->前
		while (num--)
		{
			*((char*)des + num) = *((char*)source + num);
		}
	}
	return ret;
}

我相信肯定会有人有疑问啊,memmmove看起来完全就是memcpy的升级版,那么memcpy有什么存在必要呢,这些函数其实都是很多年前设计出的了,我们现在也只能猜测,也许当时是先出的memcpy,后来有人发现了重叠的问题,然后设计出一个memmove,但其实,现在有的平台上的memcpy已经将重叠的问题解决了,例如VS,gcc等,所以其实两种都可以的,但是还有一些环境并没有将memcpy的问题解决,所以我们这两个最好都要记住。

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

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

相关文章

2023年网络安全比赛--跨站脚本攻击中职组(超详细)

一、竞赛时间 180分钟 共计3小时 二、竞赛阶段 竞赛阶段 任务阶段 竞赛任务 竞赛时间 分值 1.访问服务器网站目录1,根据页面信息完成条件,将获取到弹框信息作为flag提交; 2.访问服务器网站目录2,根据页面信息完成条件,将获取到弹框信息作为flag提交; 3.访问服务器网站目录…

javaWeb jsp

概念&#xff1a; Java Server Pages&#xff0c;Java服务端页面。 其中既可以定义 HTML、JS、CSS等静态内容&#xff0c;还可以定义 Java代码的动态内容 JSP HTML Java。最终解析为一个servlet输出给前端。 jsp实践 <dependency> <groupId>javax.servlet…

ASP.NET Core 3.1系列(24)——依赖注入框架之Autofac

1、前言 前面的博客已经介绍过ASP.NET Core中内置IoC容器的使用方法。对于规模较小的项目来说&#xff0c;内置容器完全够用。但在实际开发业务中&#xff0c;一般更推荐开发者使用Autofac作为系统的IoC容器。相较于微软提供的内置容器&#xff0c;Autofac无论是在功能性还是灵…

Python Socket联机自动匹配双人五子棋(含登录注册系统与界面,数据库连接,可作结课作业,可用于学习)

1、前言 首先&#xff0c;关于源码的获取&#xff0c;本人提供了三种方式&#xff1a; 直接从文章里面CtrlC&#xff0c;CtrlV&#xff0c;然后按照我已给的文件结构搞一下即可&#xff1b;通过积分下载上传到CSDN的资源&#xff1b;点开本人的主页&#xff0c;点击“查看详细…

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

目录 思维导图&#xff1a; 字符串与内存函数 求字符串长度 strlen 长度不受限制的字符串函数 strcpy strcat strcmp 长度受限制的字符串函数介绍 strncpy strncat strncmp 字符串查找 strstr strtok 错误信息报告 strerror perror 字符操作 内存操作函数 …

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;中间 不能&…