• 字符串函数以及内存函数的模拟实现(万字总结)



    在这里插入图片描述

    字符串函数

    作用对象是字符串。
    头文件是

     #include
    
    • 1

    🎃求字符串长度

    💡strlen

    🎉strlen函数介绍

    顾名思义:求的是字符串的长度 。

    在这里插入图片描述

    size_t 是unsigned int 通过重命名后的类型名

    注意事项
    1.与sizeof区分

    strlen接收字符串的地址,从该地址往后计算字符的个数直到’\0‘结束,‘\0’不算在个数内。
    注意与sizeof区分,用sizeof求字符串的大小的时候,’\0’是要被计算进去的。因为sizeof求的是类型所占空间的大小单位是字节。(sizeof关注点在空间,strlen关注点在’\0’)

    所以对 char str[] = { ‘a’,‘b’,‘c’};求str字符串长度是无意义的。求出来的结果是随机值。

    2.注意返回类型

    返回类型是无符号的

    来看下面这段代码,请问输出结果是什么?

    #include
    #include
    int main()
    {
    	char str1[] = "asdasf";
    	char str2[] = "abda";
    	if (strlen(str1) - strlen(str2) > 0)
    	{
    		printf(">\n");
    	}
    	else
    	{
    		printf("<\n");
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    运行结果

    在这里插入图片描述

    原因很简单:无符号数减无符号数得到的数仍然是无符号的。

    ✨模拟实现strlen的三种方式

    知道了strlen的原理我们来模拟实现下吧

    const 修饰指针的作用

    在写之前先说说,const在这的作用,const char* str,const修饰在* 前,表示 *str不可以被改变,str可以改变。如果改成char * const str ,const修饰在*的后面,表示str不可改变,*str可以被改变

    主函数

    #include
    int main()
    {
    	char arr[] = "abcdef";
    	size_t ret = my_strlen(arr);
    	printf("%u", ret);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    方法一:遍历法(计数器的方法)

    size_t my_strlen(const char* str)
    {
    	int count = 0;
    	while (*str != '\0')
    	{
    		str++;
    		count++;
    	}
    	return count;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    方法二:指针-指针

    不了解指针-指针的请点击这里

    详解数组与指针的那些知识 一

    size_t  my_strlen(const char* str)  
    {          
    	char* start = str;
    	while (*str!='\0')
    	{
    		str++;
    	}
    	return str - start;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    不理解的可以点击链接看看那篇博客在结合这个图片看看

    在这里插入图片描述

    方法三:函数递归

    size_t my_strlen(const char* str)
    {
    	if (*str != '\0')
    		return 1 + my_strlen(str + 1);
    	else
    		return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    看图片理解递归实现

    在这里插入图片描述

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

    💡strcpy

    🎉介绍strcpy

    这里是引用

    将source指向的字符串拷贝到destination(目标空间)指向的字符串中

    注意事项

    以下面的例子为例:将str2拷贝到str1 【 strcpy(str1,str2) (错误的拷贝的例子)】

    1.

    destination(str1)指向的空间必须足够大,不然会造成数组越界访问。

      char str1[7]="abcdef";
      char str2[10]="abcdefg";
    
    • 1
    • 2

    str1数组大小7个字节,明显的str2的字符长度的大小是大于7,那么拷贝的时候,那么就会造成非法访问。

    2.

    拷贝的时候,也会把source中的‘\0’一起拷贝到destination。所以source必须是以‘\0’结尾,不然也会造成非法访问。

    ✨模拟实现strcpy

    主函数

    #include
    #include//assert的头文件
    int main()
    {
    	char arr1[] = "xxxxxxxxxxx";
    	char arr2[] = "abcdef";
    	printf("%s", my_strcpy(arr1, arr2));
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    char*  my_strcpy(char* dest, const char* source)
    {                           
    	char* ret = dest;  //需要返回目的地址,要保存一下
    	
    	//assert()  ()里为真,才执行,否则报错	                        
    	//防止接收的是NULL
    	assert(dest && source); 
    
        //这里用到了,'\0'的ASCLL码值为0,为0是假
    	//先执行内部表达式(先赋值),在判断真假。
    	while (*dest++=*source++)
    	{
    		;
    	}
    	return  ret;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    💡strcat

    🎉介绍strcat

    在这里插入图片描述

      char str1[7]="abcdef";
      char str2[10]="abcdefg";
    
    • 1
    • 2

    strcat(str1,str2) ;将str2(destnation)追加到str1(source)中。

    注意事项

    从哪开始追加?

    从str1中的’\0’处开始时追加,追加结束,要以’\0’结尾

    在这里插入图片描述

    在这里插入图片描述

    空间问题
    str1的空间大小必须足够大,像这里,str1[7]小于str2[10],拷贝的时候会有问题。

    对str2有什么要求?

    需要’\0’结尾,不然拷贝的时候会越界。

    在这里插入图片描述

    能否自己追加自己?答案是不能。

    在这里插入图片描述

    ✨模拟实现strcat

    主函数

    #include
    #include
    #include
    int main()
    {
        char str1[20] = "I love ";
        char str2[6] = "you.";
        //printf("%s\n", strcat(str1, str2));
        printf("%s\n", MyStrcat(str1, str2));
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    char* MyStrcat(const char* dest,const char* sour)
    {
    	char* s1 = dest;
    	char* s2 = sour;
    	while (*s1)//找 \0
    	{
    		s1++;
    	}
    	while (*s1++ = *s2++)
    	{
    		;
    	}
    	return dest;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    💡strcmp

    🎉介绍strcmp

    在这里插入图片描述

    功能:字符串的比较,是一个字符一个字符的比较。比较的是字符所对应的ASCLL

    在这里插入图片描述

    返回值:
    str1>str2 返回大于0的数
    str1 str1=str2 返回0

    ✨模拟实现strcmp

    Vs中返回的是1,-1,0

    int MyStrcmp(const char* str1, const char* str2)
    {
    	assert(str1 && str2);
    	char* s1 = str1;
    	char* s2 = str2;
    	while (*s1 == *s2)
    	{
    		if (*s1 == '\0')
    		{
    			return 0;
    		}
    		s1++;
    		s2++;
    	}
    	if (*s1 > *s2)
    	{
    		return 1;
    	}
    	else
    	{
    		return -1;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里插入图片描述

    也可以不返回1,-1,0

    int MyStrcmp(const char* str1, const char* str2)
    {
    	assert(str1 && str2);
    	char* s1 = str1;
    	char* s2 = str2;
    	while (*s1 == *s2)
    	{
    		if (*s1 == '\0')
    		{
    			return 0;
    		}
    		s1++;
    		s2++;
    	}
    	//对应的ASCLL相减
    	return *s1 - *s2;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在这里插入图片描述

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

    💡strncpy

    🎉介绍strncpy

    在这里插入图片描述

    功能:和strcpy差不多,就添加了需要拷贝多少(num)个字符

    注意事项

    和上面的strcpy一样,还要补充的是,当num大于source所指向字符串的长度时,多出来的个数在拷贝的时候补‘\0’

    ✨模拟实现strncpy

    主函数

    #include
    #include
    #include
    int main()
    {
    	char str1[12] = "I love ";
    	char str2[7] = "you.";
    	//strncpy(str1, str2, 8);
    	my_strncpy(str1, str2, 2);
    	printf("my:%s\n", str1);
    	strncpy(str1, str2,2);
    
    	printf("%s\n", str1);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    char* my_strncpy(char* dest, const char* sour, size_t num)
    {
    	assert(dest && sour);
    	char* ret = dest;//保存起始地址
    	int len = strlen(sour);
    	int k = num - len;
    	//"I love "
    	//"you."
    	if (num > len)
    	{
    		while (len--)
    		{
    			*dest++ = *sour++;
    		}
    		//超出长度置为'\0'
    		while (k--)
    		{
    			*dest++ = '\0';
    		}
    	}
    	else
    	{
    		while (num--)
    		{
    			*dest++ = *sour++;
    		}
    	}
    	return ret;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    在这里插入图片描述

    💡strncat

    🎉介绍strncat

    在这里插入图片描述

    功能:向目标字符串追加num个字符

    注意事项

    1.和strcat大体一样,从目标字符串的‘\0’开始追加,追加结束会添加’\0’。同样也需要,目标字符串的空间足够大。
    2.与strcat不同的是,strncat,可以自己追加自己。

    ✨模拟实现strncat

    主函数

    #include
    #include
    #include
    int main()
    {
    	char str1[20] = "I love ";
    	char str2[10] = "you.";
    	strncat(str1, str2, 2);
    	printf("%s\n", str1);
    
    	my_strncat(str1, str2, 2);
    	printf("my:%s\n", str1);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    char* my_strncat(char* dest, char* sour, size_t num)
    {
        assert(dest && sour);
    	char* ret = dest;
    	//找到目标空间的'\0'
    	while (*dest)
    	{
    		dest++;
    	}
    	//进行追加,sour追加到自身的'\0'结束循环
    	while (num-- && *sour !='\0')
    	{
    		*dest++ = *sour++;
    	}
    	return ret;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述

    💡strncmp

    🎉介绍strncmp

    在这里插入图片描述

    和strcmp差不多,比较字符的大小,返回值也是一样,只比较num个字符。

    ✨模拟实现strncmp

    主函数

    int main()
    {
    	printf("%d\n", MyStrncmp("abcd", "abfd", 5));
    	printf("%d\n", MyStrncmp("abcd", "abbd", 5));
    	printf("%d\n", MyStrncmp("abcd", "abcd", 5));
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    int MyStrncmp(const char* str1, const char* str2,size_t num)
    {
    	assert(str1 && str2);
    	char* s1 = str1;
    	char* s2 = str2;
    	while (*s1 == *s2 && num--)
    	{
    		if (*s1 == '\0')
    		{
    			return 0;
    		}
    
    		if (num != 0)
    		{
    			s1++;
    			s2++;
    		}
    	}
    	if (*s1 > *s2)
    	{
    		return 1;
    	}
    	else if (*s1 < *s2)
    	{
    		return -1;
    	}
    	else
    		return 0;
    		
       	//也可以这样
    	//return *s1 - *s2;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    🎃字符串查找

    💡strstr

    🎉介绍strstr

    在这里插入图片描述

    在字符串str1中找子串str2,找到了并返回起始地址,找不到则返回NULL
    该起始地址为,主串从第几个字符开始与str2匹配。
    例如:

    在这里插入图片描述
    在这里插入图片描述

    KMP算法详解和BF算法

    过程如何来的我就不在细说啦,都在链接中的那篇博客。

    ✨模拟实现strstr(KMP难)

    主函数

    int main()
    {
    	char str1[10] = "abcdcaf";//4
    	char str2[5] = "dc";//2
    	//printf("%s\n",strstr(str1, str2));
    	printf("%s\n",MyBFstrstr(str1, str2));
    	//char* p = MyKMPStrstr(str1, str2);
    	//printf("%s\n",p);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    BF算法(暴力求解)两种实现

    char* MyBFstrstr(char* str1, char* str2)
    {
    	//数组形式
    	//int i = 0;
    	//int j = 0;
    	//int p = 0;//记录主串的起始位置
    	//int len1 = strlen(str1);
    	//int len2 = strlen(str2);
    	i,j自增是有条件的,必须相同的时候,所以不要用for循环
    	//while (i < len1 && j < len2)
    	//{
    	//	//"aabbcde", "cde"
    	//	i = p;
    	//	j = 0;
    	//	//相同的情况下
    	//	while (str1[i] == str2[j] && str2[j] != '\0')
    	//	{
    	//		i++;
    	//		j++;
    	//	}
    	//	//不相同的情况下2中情况
    	//	if (str2[j] == '\0')
    	//	{
    	//		return str1 + p;
    	//	}
    	//	p++;
    	//}
    	//return NULL;
    
    //指针形式
    
    	char* s1 = str1;//遍历搜寻
    	char* s2 = str2;//遍历搜寻
    	char* p = str1;//记录主串起始位置
    	while (*p)
    	{
    		//"aabbcde", "cde"
    		s1 = p;//回退到当前起始位置
    		s2 = str2;//回退到起始位置
    		//*s2 !='\0' 必须得有
    		//如果*s1 == *s2 == '\0'那么会出错
    		while (*s1 == *s2 && *s2 != '\0')
    		{
    			s1++;
    			s2++;
    		}
    		//找到
    		if (*s2 == '\0')
    		{
    			return p;
    		}
    		//未找到
    		p++;
    	}
    	//遍历完未找到
    	return NULL;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    在这里插入图片描述

    在这里插入图片描述

    KMP算法

    void GetNext(char* str2, int* next, int len2)
    {
    	next[0] = -1;
    	next[1] = 0;
    	int i = 2;
    	int k = 0;//记录当前下标的前一个返回地址
    	//"a  b  c  d  c  a  f"
    	//"d  c"
    	//-1  0  0  0  0
    	while (i < len2)
    	{
    		if (str2[i - 1] == str2[k] || k == -1)
    		{
    			next[i] = k + 1;
    			k++;
    			i++;
    		}
    		else
    		{
    			k = next[k];
    		}
    	}
    }
    
    
    char* MyKMPStrstr(char* str1, char* str2)
    {
    	if (*str2 == '\0')
    	{
    		return NULL;
    	}
    	int len1 = strlen(str1);
    	int len2 = strlen(str2);
    	int i = 0;
    	int j = 0;
    	int* next = (int*)malloc(sizeof(int) * len2);
    	GetNext(str2, next, len2);
    	while(i < len1 && j < len2)
    	{
    		if (str1[i] == str2[j] || j== -1)
    		{
    			j++;
    			i++;
    		}
    		else
    		{
    			j = next[j];
    		}
    	}
    	if (i == len1)
    	{
    		return NULL;
    	}
    	return str1 + (i - j);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    在这里插入图片描述

    💡strtok

    🎉介绍strtok

    在这里插入图片描述

    将字符串(str)分割,delimiters指向的是分割元素的集合(数组)
    根据什么分割?根据你分割符来分割,你的分隔符可能有多个,因此是个数组。
    例如:

    	char str1[] = "aaa.aa@bbb.cc@ccc.aa.cccdd.d.@adf";
    	char str2[] = "@.";
    
    • 1
    • 2

    str1就是要分割的字符串,str2是分隔符的集合。
    怎么实现的呢?
    第一次调用:在str1中找分割符,找到了,将这个位置标记,改为’\0’,返回地址起始地址。
    第二次调用:从这个标记的位置处开始向后查找,找到了,继续标记,再改为‘\0’,返回地址(前一次标记的地址+1,为什么加一呢,因为前一次标记的地址是’\0’)。第三次…第四次…
    直到字符串中找不到分隔符就返回NULL

    进行分割后

    char str1[] = "aaa\0aa\0bbb\0cc\0ccc\0aa\0cccdd\0d\0\0adf";
    
    • 1

    巧妙的使用方法

    int main()
    {
    	char str1[] = "aaa.aa@bbb.cc@ccc.aa.cccdd.d.@adf";
    	char str2[] = "@.";
    	char* arr = NULL;
    	for (arr = strtok(str1, str2); arr != NULL; arr = strtok(NULL, str2))
    	{
    		printf("%s\n", arr);
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述

    一般分割后原来的字符串会被破环掉,一般拷贝后,在进行分割。

    ✨模拟实现strtok(难)

    主函数

    int main()
    {
    	char str1[] = "@@..aaa.aa@bbb.cc@ccc.aa.cccdd.d.@adf";
    	char str2[] = "@.";
    	char* arr = NULL;
    	//for (arr = strtok(str1, str2); arr != NULL; arr = strtok(NULL, str2))
    	//{
    	//	printf("%s\n", arr);
    	//}
    	for (arr = my_strtok(str1, str2); arr != NULL; arr = my_strtok(NULL, str2))
    	{
    		printf("%s\n", arr);
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    char* my_strtok(char* str, char* sep)
    {
    	//标记地址
    	static char* p = NULL;
    
    	//标记不存在分隔符的情况
    	static int t = 0;
    	if (t)
    		return NULL;
    	//二次以上调用,更改地址
    	if (str == NULL)
    	{
    		str = p;
    	}
    
    	int i = 0;
    	int j = 0;
    	int len2 = strlen(sep);
    	int len1 = strlen(str);
    	//第一次就不存在分割符的情况
    	if (len2 == 0)
    	{
    		t = 1;
    		return str;
    	}
    
    	//@@..aaa.aa@..bbb.cc@ccc.aa.cccdd.d.@adf
    	//找连续分隔符
    	for (j = 0; j < len2; j++)
    	{
    		while (*str == sep[j])
    		{
    			str++;
    			//防止下一个位置还是同一个分隔符
    			j--;
    			break;
    		}
    	}
    
    	//用来标记,找到分隔符
    	int flag = 0;
    
    	//因为经过找连续分割符后,str可能已经改变,那么len1的长度也会变化。
    	len1 = strlen(str);
    
    	//遍历主串放在外层循环会更简单
    	for (i = 0; i < len1 && str[i] != '\0'; i++)
    	{
    		//@@..aaa.aa@bbb.cc@ccc.aa.cccdd.d.@adf
    		//@.
    		if (flag)
    			break;
    		for (j = 0; j < len2; j++)
    		{
    			if (!flag)
    			{
    				if (str[i] == sep[j])
    				{
    					
    					flag = 1;
    					//分割符,改为'\0'
    					str[i] = '\0';
    
    					//标记位置
    					p = &str[i + 1];
    					break;
    				}
    			}
    		}
    	}
    	if (i == len1)
    		t = 1;
    	return str;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74

    在这里插入图片描述
    在这里插入图片描述

    🎃错误信息报告

    💡strerror

    🎉介绍strerror

    在这里插入图片描述

    返回错误码对应的起始位置。

    在这里插入图片描述

    可以在动态内存,与文件相关操作,等其他方面使用。这里举一个动态内存的例子

    errno,是错误码变量,在的头文件中,如上图的0,1,2,3,4都是错误码,如果程序出错,errno就等于对应的错误码值。

    在这里插入图片描述

    这时候程序errno的值是12,12这个错误码所对应的错误信息的起始地址是Not enough space的起始地址。

    🎃内存操作函数

    内存函数可以操作任意类型的。

    头文件

    #include
    
    • 1

    💡memcpy

    🎉介绍memcpy

    在这里插入图片描述

    从source中拷贝num个字节到destnation中。
    为什么可以拷贝任意类型的呢?原因很简单,void* 像回收站可以接收任意类型的地址,不过它不可直接使用,只能通过强制类型转化后才可使用。
    这里要注意的是num个字节拷贝

    ✨模拟实现memcpy

    主函数

    int main()
    {
    	int arr1[] = { 0x11223344,0x11223344,0x11223344 };
    	int arr2[4] = { 0 };
    	//memcpy(arr1, arr2, 3);
    	my_memcpy(arr1, arr2, 3);//3个字节,不是3个元素
    	for (int i = 0; i < sizeof(arr1) / sizeof(arr1[0]); i++)
    	{
    		printf("%x ", arr1[i]);
    	}
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    void* my_memcpy(void* dest, void* src, size_t num)
    {
    	//0x11223344
    	void* ret = dest;
    	while (num--)
    	{
    		*(char*)dest = *(char*)src;
    
    		// 这样写有的编译器可能过不去
    		//((char*)dest)++;
    		//((char*)src)++;
    		
    		//一般这样写
    		dest = (char*)dest + 1;
    		src = (char*)src + 1;
    	}
    	return ret;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述

    不过我们这样实现的memcpy,存在一定的问题,因为在自己拷贝自己的时候,出现重叠的部分,拷贝达不到效果

    在这里插入图片描述

    (str1 + 3, str1, 5)拷贝后正确的结果是 abcabcdeijk,但我们没能实现。

    这就要引入我们的memmove了

    💡memmove

    🎉介绍memmove

    在这里插入图片描述

    一般是用在自己拷贝自己的情况,拷贝不同的变量(同一类型)也是可以的

    在这里插入图片描述

    vs中的memcpy,也可以实现自我拷贝。

    在这里插入图片描述

    按照c语言对memcpy,memmove的定义来看。memcpy处理的是拷贝不同的变量(同一类型),memmove处理的是拷贝自己的情况。

    不管怎么分,我们先来实现自己拷贝自己的情况。

    在这里插入图片描述
    在这里插入图片描述

    ✨模拟实现memmove

    主函数

    #include
    #include
    
    int main()
    {
    	char  str1[] = "abcdefghijk";
    	char str2[] = "XXXXXX";
    	my_memmove(str1, str1 + 3, 5);
    	printf("%s\n", str1);
    
    	char  str3[] = "abcdefghijk";
    	my_memmove(str3+ 2, str3 + 5, 5);
    	printf("%s\n", str3);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    void* my_memmove(void* dest, void* src, size_t num)
    {
    	void* ret = dest;
    	if (dest == src)
    		return ret;
    	if (src < dest)
    	{
    		//abcde
    		//defgh
    		//从后向前拷贝
    		dest = (char*)dest + num - 1;
    		src = (char*)src + num - 1;
    		while (num--)
    		{
    			//abcdefghijk
    			*(char*)dest = *(char*)(src);
    			dest = (char*)dest - 1;
    			src = (char*)src - 1;
    		}
    	}
    	else 
    	{
    		//fghij
            //defgh
    		//从前向后拷贝
    		while (num--)
    		{
    			*(char*)dest = *(char*)src;
    			dest = (char*)dest + 1;
    			src = (char*)src + 1;
    		}
    	}
    	return ret;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    💡memset

    🎉介绍memset

    在这里插入图片描述

    功能:ptr指向的内存块前num个字节设置为"value“(value可以是字符也可以是数字)

    一般是可用来对数组初始化
    例如

    在这里插入图片描述

    💡memcmp

    🎉介绍memcmp

    在这里插入图片描述

    和strncmp类似,都是按一个字节一个字节的比较,比较的是ASCLL值。不过memcmp可以比较不同类型的,strncmp只能比较字符串

    返回值:

    当ptr1>ptr2,返回大于0的数
    当ptr1 当ptr1=ptr2,返回0

    ✨模拟实现memcmp

    主函数

    #include
    int main()
    {
    	char arr[] = "11223344";
    	char arr1[] = "10223344";
    	int ret = my_memcmp(arr, arr1, 3);
    	printf("%d\n", ret);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    int my_memcmp(const void* str1, const void* str2, size_t num)
    {
    	while (num--)
    	{
    		if ((char*)str1 > (char*)str2)
    		{
    			return 1;
    		}
    		else if ((char*)str1 < (char*)str2)
    		{
    			return -1;
    		}
    		str1 = (char*)str1 + 1;
    		str2 = (char*)str2 + 1;
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    🛴结束语

    测试用例可能不太全面,模拟实现大家参考即可,要是有错误请告诉我下下❤❤
    讲了一推的函数,一堆的实现大家可以自己模拟实现,加深自己对这些函数的理解

  • 相关阅读:
    2021年中国研究生数学建模竞赛D题——抗乳腺癌候选药物的优化建模
    WWDC22 前瞻:iOS 16、iPadOS 16等五大操作系统亮相,AR/VR头显将缺席?
    Delta tuning(只抓核心)
    还在用 Chrome? Edge 已成为我的主力浏览器
    【Linux】管道
    【计算机毕业设计】python学生成绩补考通知管理系统
    java基础讲义03
    Docker无介绍快使用,docker拉取zipkin(十四)
    金仓数据库KingbaseES安全指南--2.2. KingbaseES对数据库安全威胁的预防
    入局AI手机 苹果公布Apple Intelligence
  • 原文地址:https://blog.csdn.net/m0_64212811/article/details/126846122