【C语言】字符函数,字符串函数,内存函数及其模拟实现

news2024/11/26 9:14:07

文章目录

  • 求字符串长度
    • strlen
  • 长度不受限制的字符串函数
    • strcpy
    • strcat
    • strcmp
  • 长度受限制的字符串函数
    • strncpy
    • strncat
    • strncmp
  • 字符串查找函数
    • strstr
    • strtok
    • strerror
  • 字符函数
    • 字符分类函数
    • 字符转换函数
  • 内存操作函数
    • memcpy
    • memmove
    • memset
    • memcmp

求字符串长度

strlen

函数功能

求字符串长度,求一个字符串中字符的个数(不包括’\0’)

函数原型

size_t strlen ( const char* str )

size_t 是函数的返回类型

char* s是函数参数

函数的使用

#include <stdio.h>
#include <string.h>
int main()
{
	char arr[] = "abcdef";
	int len = strlen(arr);
	printf("%d\n", len);
	return 0;
}

在这里插入图片描述

模拟实现

1.计数器实现

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

//求字符串长度
size_t my_strlen(const char* str)
{
	//检查指针有效性
	assert(str);
	int count = 0;
	while (*str != '\0')
	{
		count++;
		str++;
	}
	return count;
}

2.指针-指针的方式

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

//求字符串长度
size_t my_strlen(const char* str)
{
	//检查指针有效性
	assert(str);
	char* head = str; //记录字符串起始位置
	//找到字符串结束位置
	while (*str != '\0')
	{
		str++;
	}
	return str - head; //指针-指针得到字符的个数
}

3.递归的方式

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

//求字符串长度
size_t my_strlen(const char* str)
{
	//检查指针有效性
	assert(str);

	if (*str == '\0')
		return 0;
	else
		return 1 + my_strlen(str + 1);
}

注意事项

字符串已经 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包含 ‘\0’ )

参数指向的字符串必须要以 ‘\0’ 结束,否则得到的是一个随机值,没有意义。(strlen会一直往后找,直到遇到’\0’才结束)

注意函数的返回值为size_t,是无符号的( 易错 ,可能出现算数转换)

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

strcpy

函数功能

字符串拷贝,把一个字符串里面的内容拷贝到另一个字符串中(包括’\0’)

函数原型

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

char* 是函数的返回值类型,返回的是目标空间的起始地址

source 是要拷贝的字符串

destination 是目标空间(字符串拷贝到的地方)

函数使用

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

在这里插入图片描述

模拟实现

初阶

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

//字符串拷贝
char* my_strcpy(char* dest, const char* src)
{
	//检查指针有效性
	assert(dest && src);
	char* ret = dest; //记录目标空间的起始地址
	while (*src != '\0')
	{
		*dest++ = *src++;
	}

	*dest = *src;  //拷贝字符'\0'
	return ret;
}

进阶

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

//字符串拷贝
char* my_strcpy(char* dest, const char* src)
{
	//检查指针有效性
	assert(dest && src);
	char* ret = dest;//记录目标空间的起始地址
	//全部字符和'\0'拷贝到目标空间中
	//*dest++ = *src++的返回值为dest指向的内容,当到'\0'时,返回值为0,结束循环
	while (*dest++ = *src++)
	{
		;
	}
	return ret;
}

注意事项

源字符串必须以 ‘\0’ 结束

会将源字符串中的 ‘\0’ 拷贝到目标空间

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

目标空间必须可变,不可变则不能拷贝

strcat

函数功能

字符串追加,在一个字符串的末尾追加另外一个字符串(包括’\0’)

函数原型

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

char* 是函数的返回值,返回的是目标空间的起始地址

source 是要追加的字符串

destination 是目标空间(被追加的字符串)

函数使用

#include <stdio.h>
#include <string.h>
int main()
{
	char arr1[12] = "hello ";
	char arr2[] = "world";
	strcat(arr1, arr2);
	printf("%s\n", arr1);
	
	return 0;
}

在这里插入图片描述

模拟实现

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

//字符串追加
char* my_strcat(char* dest, const char* src)
{
	//检查指针有效性
	assert(dest && src);
	char* ret = dest;  //记录目标空间的起始地址
	//找到目标空间的末尾'\0'
	while (*dest !='\0')
	{
		dest++;
	}
	//拷贝字符串
	while (*dest++ = *src++)
	{
		;
	}
	return ret;
}

注意事项

源字符串必须以 ‘\0’ 结束

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

目标空间必须可修改

字符串不能自己给自己追加(追加会覆盖末尾的’\0’,从而导致死循环)

strcmp

函数功能

字符串比较,以字节为单位比较(比较ASCII值)两个字符串的大小

函数原型

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

int 函数的返回值 : >0 : str > str2

​ =0 : str1 = str2

​ <0 : str1 < str2

str1 str2 用于比较的两个字符串

函数的使用

#include <stdio.h>
#include <string.h>
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abcdf";
	int ret = strcmp(arr1, arr2);
	printf("%d\n", ret);
	return 0;
}

在这里插入图片描述

模拟实现

方法1

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

//比较字符串大小
int my_strcmp(const char* str1, const char* str2)
{
	//检查指针有效性
	assert(str1 && str2);
	//字符相等一直继续比较
	while (*str1 == *str2)
	{
		//大小相等且*str1或str2为'\0',说明都为'\0',则说明相等
		if (*str1 == '\0')
			return 0;
		str1++;
		str2++;
	}
	//不相等则返回差值
	return (*str1 - *str2);
}

方法2

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

//比较字符串大小
int my_strcmp(const char* str1, const char* str2)
{
	//检查指针有效性
	assert(str1 && str2);
	//相等且不为'\0'指针一直往后走
	while (*str1 == *str2  && *str1 != '\0' && *str2 != '\0')
	{
		str1++;
		str2++;
	}
	//此时情况为字符不相等(*str1=='\0' || *str2 =='\0' || 
	*str1 == *str2 =='\0' || * str1 != str2且不为'\0')则可以返回差值
	return *str1 - *str2;

注意事项

标准规定:

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

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

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

对每一对字符进行比较,直到遇到不相等的字符或者都到字符串的末尾时函数结束

比较的每是一对字符的ASCII值

长度受限制的字符串函数

由于strcpy,strcat,strcmp等字符串函数存在安全隐患(目标空间小于源空间等问题),C语言针对这些问题提供了几个相对安全的字符串函数,即strncpy,strncat,strncmp,这些字符串函数相对于strcpy,strcat,strcmp函数多了一个参数,用于指定操作的字节数。但是注意的是,strncpy,strncat,strncmp函数只是相对安全,并不是绝对安全,多一个参数只是起到了提醒的作用。

strncpy

函数功能

字符串拷贝,把一个字符串的num个字节的内容拷贝到另一个字符串中。

函数原型

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

char* 是函数的返回值,返回的是目标空间的起始地址

source是要拷贝的字符串

destination是目标空间

num是要拷贝的字节数

函数使用

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

int main()
{
	char arr1[] = "abcdef";
	char arr2[10] = { 0 };
	strncpy(arr2, arr1, 6);
	printf("%s\n", arr2);
	return 0;
}

在这里插入图片描述

模拟实现

方法1

#include <stdio.h>
#include <assert.h>
//字符串拷贝
char* my_strncpy(char* dest, const char* src, int num)
{
	//检查指针的有效性
	assert(dest && src);
	char* ret = dest;  //记录目标空间的起始地址
	while (num--)
	{
		*dest = *src;
		//如果*dest为'\0',说明src的结束字符赋值给了dest,这种情况下源字符串的长度小于num
		if (*dest == '\0')
		{
			//如果源字符串的长度小于num,则在目标空间的后面追加'\0',直到num个
			while (num--)
			{
				*dest++ = '\0';
			}
			break;
		}
		dest++;
		src++;
	}
	*dest = '\0';    //在dest的末尾补上'\0'
	return ret;
}

方法2

#include <stdio.h>
#include <assert.h>
//字符串拷贝
char* my_strncpy(char* dest, const char* src, int num)
{
	//检查指针的有效性
	assert(dest && src);  
	char* ret = dest;  //记录目标空间的起始地址

	//拷贝字符串直到'\0'
	while ((*dest = *src) != '\0' && num)
	{
		dest++;
		src++;
		num--;
	}

	//如果源字符串的长度小于num,则在目标空间的后面追加'\0',直到num个
	if (num)
	{
		while (--num)
		{
			*dest++ = '\0';
		}
	}

	*dest = '\0';  //在dest的末尾补上'\0'
	return ret;
}

注意事项

拷贝num个字节的内容到目标空间,如果源字符串小于num,则拷贝源字符串后在目标空间追加0,直到num个

src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳num的长度和’\0’

strncat

函数功能

字符串追加,把一个字符串中的num个字节的内容追加到另一个字符串的末尾,并在最后加上’\0’

函数原型

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

char* 是函数的返回值,返回目标空间的起始地址

destination 是目标空间

source 是要追加的字符串

num是要追加的字节数

函数使用

#include <stdio.h>
#include <string.h>
int main()
{
	char arr1[12] = "hello ";
	char arr2[] = "world";
	strncat(arr1, arr2, 5);
	printf("%s", arr1);
	return 0;
}

在这里插入图片描述

模拟实现

#include <stdio.h>
#include <assert.h>
//字符串追加
char* my_strncat(char* dest, const char* src, size_t num)
{
	//检查指针的有效性
	assert(dest && src);
	char* ret = dest;    //记录目标空间的起始地址

	//找到目标空间的末尾'\0'
	while (*dest != '\0')
	{
		dest++;
	}

	//拷贝字符串
	while (num--)
	{
		*dest = *src;
		//如果源字符串的长度小于num,则在目标空间的后面追加'\0',直到num个
		if (*dest == '\0')
		{
			while (num--)
			{
				*dest++ = '\0';
			}
		}
		dest++;
		src++;

	}
	*dest = '\0';  //在dest的末尾补上'\0'
	return ret;
}

注意事项

将源字符串中的num个字节的内容追加到目标字符串的末尾,并在末尾加’\0’

如果源字符串的长度小于num,则只复制到终止空字符的内容

strncmp

函数功能

字符串比较,比较两个字符串前num个字节的大小

函数原型

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

int 函数的返回值 : >0 : str > str2

​ =0 : str1 = str2

​ <0 : str1 < str2

str1 str2 用于比较的两个字符串

num是要比较的字节数

函数使用

#include <stdio.h>
#include <string.h>
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abc";
	int ret = strncmp(arr1, arr2, 3);
	printf("%d\n", ret);
	return 0;
}

在这里插入图片描述

模拟实现

#include <stdio.h>
#include <assert.h>
//字符串比较
int my_strncmp(const char* str1, const char* str2, size_t num)
{
	//检查指针的有效性
	assert(str1 && str2);
    //不相等或者num为0时结束
	while (num && *str1 == *str2)
	{
		str1++;
		str2++;
		num--;
	}

	//比较了num个且相等
	if (num == 0)
	{
		return 0;
	}
	//不相等则返回差值
	return (*str1 - *str2);
}

注意事项

标准规定:

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

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

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

对每一对字符进行比较,直到遇到不相等的字符或者都到字符串的末尾时函数结束

比较的每是一对字符的ASCII值

字符串查找函数

strstr

函数功能

查找子串,查找一个字符串是否包含子串

函数原型

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

char* 是函数的返回值,返回的是字符串子串的起始位置,若找不到,则返回NULL

str1是要搜索的字符串

str2为子串

函数使用

#include <stdio.h>
#include <string.h>
int main()
{
	char arr1[] = "abbcdef";
	char arr2[] = "bbc";
	char* ret = strstr(arr1, arr2);
	printf("%s\n", ret);
	return 0;
}

在这里插入图片描述

模拟实现

#include <stdio.h>
#include <assert.h>
//查找子字符串
char* my_strstr(const char* str1, const char* str2)
{
	//检查指针的有效性
	assert(str1 && str2);
	//如果中途匹配失败需要返回str2的起始位置,所以用其他变量保存str2,保证str2的首地址不会丢失
	const char* s1 = str1;
	const char* s2 = str2;
	//用来记录每次第一个字符匹配成功的位置
	const char* p = str1;
	while (*p != '\0')
	{
		s1 = p; //从p处开始往后匹配
		s2 = str2; //每次匹配后s2回到str2起始位置
		while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2)
		{
			s1++;
			s2++;
			//如果不相等处s2为'\0'则说明匹配成功
			if (*s2 == '\0')
			{
				return (char*)p;
			}
		}
		//否则这一次匹配失败,则需要从下一个位置重新开始匹配
		p++;
	}
	//字符串都找完了,说明没有找到则返回NULL
	return NULL;
}

注意事项

被查找的字符串和子串都不能为空字符串,且都以’\0’结尾

如果查找成功,返回字符串中子字符串的起始地址,如果查找失败则返回NULL

strtok

函数功能

字符串分割,把一个字符串按照分割标志分割为几个字符串

函数原型

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

char* 函数返回值,strtok函数会找到str中的下一个标记,并将用’\0’结尾,返回一个指向这个标记的指针

char* str 被分割的字符串,包含了0个或多个由delimiters字符串中的一个或者多个分割字符的标记

sep 一个字符串,做分割字符的集合

函数使用

#include <stdio.h>
#include <string.h>
int main()
{
	char sep[] = "@.";
	char email[] = "123456789@qq.com";
	//因为切割之后源字符串会改变,所以我们用一个临时字符串代替
	char cp[20] = { 0 };
	strcpy(cp, email);
    //第一次传递被切割字符串的首地址
	char* ret = strtok(cp, sep);
	if (ret != NULL)
		printf("%s\n", ret);
    //第二次及以后第一个参数传递空指针NULL(strtok会记住上一次切割的位置)
	ret = strtok(NULL, sep);
	if (ret != NULL)
		printf("%s\n", ret);

	ret = strtok(NULL, sep);
	if (ret != NULL)
		printf("%s\n", ret);


	return 0;
}

在这里插入图片描述

这个我们知道目标字符串会被分割成3个字符串,所以我们调用了三次strtok函数,如果我们不知道源字符串会被分割成多少段字符串的时候,我们这个方法显然就不适用了。

我们知道,strtok函数第一次调用时需要传递目标字符串的地址,之后只需要传递空指针即可,那么我们就可以利用这个特点结合for循环的特征来使用trtok函数。

#include <stdio.h>
#include <string.h>
int main()
{
	char sep[] = "@.";
	char email[] = "123456789@qq.com";
	//因为切割之后源字符串会改变,所以我们用一个临时字符串代替
	char cp[20] = { 0 };
	strcpy(cp, email);
	//用来保存strtok函数的返回值
	char* ret = NULL; 
	for (ret = strtok(cp, sep);   //初始化部分,第一次传递被切割字符串的地址
		ret != NULL;    //判断部分,只要strtok函数的返回值不为空,说明没有分割完毕
		ret = strtok(NULL, sep))   //调整部分,第二次级以后传递NULL
	{
	//ret不为空,说明字符串没有分割完毕,继续打印
		printf("%s\n", ret);  
	}
	return 0;
}

注意事项

1.sep参数是个字符串,定义了用作分隔符的字符集合

2.第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记

3.strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)

4.strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。

5.strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。

6.如果字符串中不存在更多的标记,则返回 NULL 指针

strerror

函数功能

C语言有一系列的库函数,当这些库函数调用失败时会返回相应的错误码,而我们仅知道错误码还是不能够知道错误的原因,而sreerror函数就能够获取错误码对应的错误信息的首地址,让我们知道程序发生错误的原因

函数原型

char* strerror ( int errnum )

char* 函数返回值,返回错误码对应错误信息的首地址

errnum 错误码

函数使用

#include <stdio.h>
#include <string.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;
}

在这里插入图片描述

这里有个问题,C语言有那么多的错误信息,需要我们一个一个的去记住错误信息对应的错误码吗,其实并不用,C语言设置了一个全局的用于存放错误码的变量errno,只要调用C语言库函数发生错误,那么errno就会记录相应的错误码,所以strerror函数一般和errno配合使用,errno需要包含头文件<errno.h>

#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));
		return 1;
	}
	else
	{
		printf("文件打开成功\n");
	}
	return 0;
}

在这里插入图片描述

字符函数

字符分类函数

函数如果他的参数符合下列条件就返回真
iscntrl任何控制字符
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任何可打印字符,包括图形字符和空白字符

字符转换函数

函数返回值
tolower返回对于小写字母的ASCII值
toupper返回对于小写字母的ASCII值

内存操作函数

前面我们学习的strcpy,strcat,strcmp,strncpy,strncat,strncmp等函数都是字符串函数,只能对字符串进行相关的操作,而对于整形,浮点型,结构体等等类型的数据就需要使用到内存操作函数,常见的内存操作函数有memcpy,memmove,memset,memcmp

memcpy

函数功能

内存拷贝,将一块内存中的num个字节的内容拷贝到另一块内存中常用来处理不重叠内存数据的拷贝

函数原型

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

void* 函数返回值,返回dest内存空间的地址

void* destination 目标内存空间地址

void* source 源空间地址

size_t num 要拷贝的字节数

函数使用

#include <stdio.h>
#include <string.h>
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };
	memcpy(arr2, arr1, 40);
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr2[i]);
	}
	printf("\n");
	return 0;
}

在这里插入图片描述

模拟实现

#include <stdio.h>
#include <assert.h>
//内存拷贝
void* my_memcpy(void* dest, const void* src, size_t num)
{
	//检查指针有效性
	assert(dest && src);
	void* ret = dest;  //记录目标空间的起始地址
	//以字节为单位进行拷贝
	while (num--)
	{
		//强转为char*后进行赋值
		*(char*)dest = *(char*)src;
		//这里不要写成(char*)dest++,在某些编译器会报错,因为强制类型转换是一种临时效果
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}

注意事项

在C语言标椎中,memcpy只负责处理不重叠的内存拷贝,内存重叠的拷贝是由memmove实现的,但在有些编译器可能memcpy也实现了memmove的功能,但在某些编译器下memcpy可能就没有实现memmove的功能,所以我们在使用内存重叠的数据拷贝时尽量使用memmove函数,避免发生错误

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

这个函数在遇到 ‘\0’ 的时候并不会停下来

如果source和destination有任何的重叠,复制的结果都是未定义的

memmove

函数功能

内存移动,将一块内存数据中的内容移动覆盖到另一块内存数据,常用来处理重叠内存数据的拷贝

函数原型

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

void* 函数返回值,返回dest内存空间的地址

void* destination 目标内存空间地址

void* source 源空间地址

size_t num 要拷贝的字节数

函数使用

#include <stdio.h>
#include <string.h>
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	memmove(arr1 + 2, arr1, 20);
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
	printf("\n");
	return 0;
}

在这里插入图片描述

模拟实现

思路分析

dest和src的地址大小不同,如果我们统一像memcpy一样从前向后拷贝就会出现内存覆盖的情况,因此我们分为两种情况进行讨论:

1.dest的地址小于src的地址

在这里插入图片描述

如图,如果此时我们从后往前覆盖,7覆盖到5的位置,6覆盖到4的位置,但是当原来的5要覆盖到3的位置时,5已经被7覆盖,所以我们从前往后进行覆盖。

2.dest的地址大于src的地址

在这里插入图片描述

如图,如果我们从前往后覆盖的话,1覆盖到3,2覆盖到4,但是当原来的3要覆盖到5的时候,3的位置已经被覆盖成了1,从而造成结果不正确,所以我们从后往前覆盖。

代码实现:

#include <stdio.h>
#include <assert.h>
//内存移动
void* my_memmove(void* dest, 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);
		}
	}

	return ret;
}

注意事项

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

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

memset

函数功能

内存设置,把一块内存中的num个字节的内容设置为指定的数据

函数原型

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

void* 函数返回值,返回目标空间的地址

void* ptr 函数参数,目标字符串的起始地址

int value 函数参数,指定初始化的数

size_t num 函数参数,要初始化的字节数

函数使用

#include <stdio.h>
#include <string.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	memset(arr + 5, 0, 20);
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

在这里插入图片描述

模拟实现

#include <stdio.h>
#include <assert.h>
//内存设置
void* my_memset(void* ptr, int val, size_t num)
{
	assert(ptr);
	void* ret = ptr;  //记录目标空间的起始地址
	//一个字节一个字节的进行赋值
	while (num--)
	{
		*(char*)ptr = val;
		ptr = (char*)ptr+1;
	}
	return ret;
}

memcmp

函数功能

内存比较,比较两块内存中前num个字节的大小

函数原型

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

int 函数的返回值 : >0 : str > str2

​ =0 : str1 = str2

​ <0 : str1 < str2

str1 str2 用于比较的两个字符串

num是要比较的字节数

函数使用

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

在这里插入图片描述

模拟实现

#include <stdio.h>
#include <assert.h>
//内存比较
int my_memcmp(const void* str1, const void* str2, size_t num)
{
	//检查指针的有效性
	assert(str1 && str2);

	//不相等或者num为0时结束
	while (*(char*)str1 == *(char*)str2 && num)
	{
		str1 = (char*)str1 + 1;
		str2 = (char*)str2 + 1;
		num--;
	}
	//比较了num个且相等
	if (num == 0)
	{
		return 0;
	}
	//不相等则返回差值
	return *(char*)str1 - *(char*)str2;
}

//记录目标空间的起始地址
//一个字节一个字节的进行赋值
while (num–)
{
(char)ptr = val;
ptr = (char*)ptr+1;
}
return ret;
}


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

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

相关文章

【机器学习之模型融合】Voting投票法简单实践

目录 前言&#x1f49c; 1、使用sklearn实现投票法&#x1f494; 1.1、导入工具库&#xff0c;准备数据&#x1f495; 1.2、定义交叉验证评估函数&#x1f496; 1.3、建立基于交叉验证的benchmark、做模型选择&#x1f31f; 1.4、构建多组分类器、进行融合&#x1f4a5;…

单线程的Node.js能开发高并发服务器程序吗?

文章目录前言Nodejs的事件驱动机制EventLoop vs NSRunLoopNSRunLoopios next runloop异步/事件循坏机制的那些坑批量迁移数据原子性参考文献前言 这篇文章还是从一个在写Node.js程序中遇到的问题说起。本周在做数据库迁移的时候&#xff0c;写了下面一段代码&#xff0c;目的是…

代数与逻辑:作业四 神经网络

代数与逻辑&#xff1a;作业四 神经网络 文章目录代数与逻辑&#xff1a;作业四 神经网络一、作业要求二、简述神经网络模型三、编程实现感知机模型与二隐层神经网络1、感知机模型2、二隐层神经网络四、选择公开数据集&#xff0c;测试感知机模型与二隐层神经网络性能一、作业要…

如何高效学习?一年学完麻省理工4年计算机课程

斯科特.杨用用10天拿下线性代数&#xff0c;用1年时间学完麻省理工大学4年的计算机课程&#xff0c;他是如何做到的&#xff1f;他在这本书《如何高效学习》中做了具体阐述。 斯科特.杨很早就发现&#xff0c;在美国有一半的学生在死记硬背&#xff0c;这些学生并不知道使用整体…

动手学区块链学习笔记(二):区块链以及工作量证明算法

引言 紧接上文&#xff0c;在介绍完区块链中的加密解密以及公钥私钥等算法后&#xff0c;本篇开始正式进入区块链概念与一个简单区块链系统的实现过程介绍。 区块链技术介绍 什么是区块链&#xff1f; 区块链&#xff0c;就是一个又一个区块组成的链条。每一个区块中保存了一…

制造企业数据/经营分析框架

背景 随着大数据技术发展以及数字化转型概念的普及&#xff0c;传统企业特别是制造业&#xff0c;也开始投入人力、资金&#xff0c;建立自己的数据分析团队&#xff0c;期望通过数据分析赋能企业的发展/转型。尽管&#xff0c;国内华为、美的、海尔、三一、徐工等制造业龙头企…

挡不住,逃不过,还是阳了

自从放开后&#xff0c;身边的&#x1f40f;陆陆续续多了起来。现在都不敢在食堂吃饭了&#xff0c;每次都是打包到工位吃&#xff0c;上班时也是都戴着口罩。每天回家后都是一顿扫射&#xff0c;用医用酒精做全身消毒。但是&#xff0c;还是没挡住&#xff0c;该来的还是来了。…

Leetcode:450. 删除二叉搜索树中的节点(C++)

目录 问题描述&#xff1a; 实现代码与解析&#xff1a; 递归&#xff1a; 原理思路&#xff1a; 含有内存释放版&#xff1a; 问题描述&#xff1a; 给定一个二叉搜索树的根节点 root 和一个值 key&#xff0c;删除二叉搜索树中的 key 对应的节点&#xff0c;并保证二叉搜…

Day860.高性能数据库连接池HiKariCP -Java 并发编程实战

高性能数据库连接池HiKariCP Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于高性能数据库连接池HiKariCP的内容。 实际工作中&#xff0c;总会难免和数据库打交道&#xff1b; 只要和数据库打交道&#xff0c;就免不了使用数据库连接池。 业界知名的数据库连接池…

2023/1/15 JS-作用域与作用域链

1 作用域 理解 - 就是一块"地盘", 一个代码段所在的区域&#xff0c;它是静态的(相对于上下文对象), 在编写代码时就确定了 分类&#xff1a; 全局作用域函数作用域 没有块作用域(ES6有了) -->(java语言也有) if (true) {var a 3}console.log(a); // 3作用&am…

用互联网思维做产品,做超出用户预期的产品

做出超出用户预期的产品&#xff0c;做出让用户惊喜和兴奋的产品。超越用户期望极致体验极致服务极致产品(极致产品功能情感温度)关心、关注、尊重用户理解用户理解人性用户参与。只有深刻了解&#xff0c;深刻理解用户&#xff0c;深刻理解人性&#xff0c;才能做出好的产品。…

Maven安装教程讲解

目录一、下载安装JDK二、下载 Maven三、配置 Maven 环境变量四、配置 Maven 仓库地址五、配置 Maven 镜像六、配置 Maven JDK七、IDE配置 Maven八、IDE新建 Maven 项目九、IDE执行 Maven 命令一、下载安装JDK 教程&#xff1a;https://blog.csdn.net/weixin_43888891/article/…

【阶段四】Python深度学习09篇:深度学习项目实战:循环神经网络处理时序数据项目实战:CNN和RNN组合模型

本篇的思维导图: 项目背景 时间序列数据集中的所有数据都伴随着一个时戳,比如股票、天气数据。这个数据集,是科学家们多年间用开普勒天文望远镜观察并记录下来的银河系中的一些恒星的亮度。广袤的宇宙,浩瀚的星空在过去很长一段时间里,人类是没有办法证明系外行星…

关于一次python服务性能的问题分析定位

今天项目遇到一个比较棘手的问题&#xff0c;我们做的接口平台&#xff0c;提供了一个给用户自己编辑关键字的逻辑&#xff0c;发现对应服务的cpu基本都满了&#xff0c;并且通过扩容的方式也没有好转&#xff0c;也同样被打满。 找了测试的同学了解了下&#xff0c;发现他们使…

Enterprise JavaBean 简介

Enterprise JavaBean 简介 在顶层我们使用的框架是面向服务的&#xff0c;而在其之下的开发方法面向组件&#xff0c;最基层的便是面向对象面向过程的JAVA编程。 面向过程和面向对象是两种具体程序设计时的编程范式&#xff0c;他们没有本质区别&#xff0c;只是使用不同的方…

【Linux】Linux命令行git和Linux调试器-gdb的使用

文章目录一、Linux命令行git1. git是什么2. Gitee上创建仓库&#xff0c;克隆仓库到本地3. git三板斧二、Linux调试器-gdb的使用1. debug和release的区别2. 常用命令一、Linux命令行git 1. git是什么 git是一个开源的分布式版本控制系统&#xff0c;可以有效、高速地处理从很…

分享52个Java源码,总有一款适合您

Java源码 分享52个Java源码&#xff0c;总有一款适合您 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff0c;大家下载后可以看到。 源码下载链接&#xff1a;https://pan.baidu.com/s/1YpNL5QWwQ18Y-KRmFHFs5g?pwdqc8w …

吴恩达机器学习课程笔记:监督学习、无监督学习

1.吴恩达机器学习课程笔记&#xff1a;监督学习、无监督学习 吴恩达机器学习系列课程&#xff1a;监督学习 吴恩达机器学习系列课程&#xff1a;无监督学习 仅作为个人学习笔记&#xff0c;若各位大佬发现错误请指正 机器学习的学习算法&#xff1a;监督学习、无监督学习、半…

1591_AURIX_TC275_PMU_Flash的保护

全部学习汇总&#xff1a; GreyZhang/g_TC275: happy hacking for TC275! (github.com) 可以支持保护功能的Flash是前面文档中呼出来的几块&#xff0c;其中DFlash由于多模块公用&#xff0c;还有具体的拆分。PFlash可以进行两方面的保护&#xff0c;一个是错误的读取方式保护&…

python列表(list)底层实现

list Python内存管理中的基石 Python中所有类型创建对象时&#xff0c;底层都是与PyObject和PyVarObject结构体实现&#xff0c;一般情况下由单个元素组成对象内部会使用PyObject结构体&#xff08;float&#xff09;、由多个元素组成的对象内部会使用PyVarObject结构体 2个…