一、手写strstr
strstr函数是C语言中的一个标准库函数,用于在一个字符串中查找第一个出现的另一个字符串。如果找到,strstr函数将返回指向第一个匹配字符的指针;否则,返回NULL。strstr函数的原型位于string.h头文件中。其函数原型为:
char* my_strstr(const char* str,const char* targrt);
其中,str1是待搜索的字符串,即搜索范围。 str2是要查找的字符串。
代码如下:
# include <stdio.h>
char* my_strstr(const char* str,const char* targrt);
int main()
{
char* s = "this is an example";
char* target1 = "is";
char* target2 = "exa";
char* res1 = my_strstr(s,target1);
char* res2 = my_strstr(s,target2);
printf("res1 = : %s\n",res1);
printf("res2 = : %s\n",res2);
return 0;
}
//const char * c代表的是,指针c指向的内存的内容是不可以改变的,但是指针c是可以改变的。如果是char *const c,那么c指向的内容可以改变,但是c不能改变,即不能++和--
char* my_strstr(const char* str,const char* target)//在str中找到目标字符串target,如果找到,就返回指向匹配字符串的第一个位置,否则返回null
{
if(*target == '\0')
return (char*)str;//需要类型转换一下
while(*str != '\0')
{
char* ch1 = str;
char* ch2 = target;
while(*ch1 != '\0' && *ch2 != '\0' && *ch1 == *ch2)
{
ch1 ++;
ch2 ++;
}
if(*ch2 == '\0')
return (char*)str;
str ++;
}
return NULL;
}
二、手写strcpy
strcpy函数是C语言中的一个标准库函数,用于将一个字符串(以'\0'为结束符)复制到另一个字符串。strcpy函数的原型位于string.h头文件中。
# include <stdio.h>
char* my_strcpy(char* destination,const char* sourse);
int main()
{
char des[40];
char s[] = "this is an example";
my_strcpy(des,s);
printf("des = : %s\n",des);
printf("s = : %s\n",s);
return 0;
}
char* my_strcpy(char* destination,const char* sourse)
{
if(destination == NULL || sourse == NULL)
return destination;
char* des = destination;
while(*sourse != '\0')
{
*(des ++) = *(sourse ++);
}
*des = '\0';
return destination;
}
三、手写memmove
memmove和memcpy的功能类似,都是把一段内存段的内容复制到另一段内存区域。
只不过memmove可以处理源内存和目标内存区域重合的情况。
手写代码如下:
# include<stdio.h>
# include<stddef.h>//包含size_t
void *my_memmove(void* destination,const void *sourse,size_t num);
int main()
{
char s[] = "this is an example";
printf("s = : %s\n",s);
my_memmove(s + 4,s,3);//将s字符串的前3个字符,向后移动4个位置
printf("s = : %s\n",s);
//size_t i = 0;
//i --;
//printf("i = : %lu\n",i);//为了测试size_t数据类型的最大值。size_t数据类型是无符号的,减到0之后再往下减就会减到他的最大值,然后循环
return 0;
}
void *my_memmove(void* destination,const void *sourse,size_t num)
{
char *des = (char*)destination;//因为要一个字节一个字节的复制,char正好是一个字节,所以刚刚好
const char* src = (const char*)sourse;
//下面要处理可能的内存重叠情况,即des和src的内存有可能是部分重叠的,这样在复制的过程中就要特别注意顺序,不然有可能会把数据覆盖掉.这部分画个图就明白了
//des地址比src小,在src的前面,这个时候按照地址从小到大复制
if(des < src)
{
for(size_t i = 0;i < num;++ i)
{
des[i] = src[i];
}
}else{
for(size_t i = num;i > 0;-- i)
{
des[i - 1] = src[i - 1];
}
/*
//下面这种写法会内存越界
for(size_t i = num - 1;i >= 0;-- i)//size_t数据类型是无符号的,减到0之后再往下减就会减到他的最大值,然后循环,然后就越界了
{
des[i] = src[i];
}*/
}
return destination;
}
memmove函数返回指向目标区域内存的指针。
结果:
memmove的关键就在于处理内存重叠,也就是需要判断源地址和目标地址之间的大小关系,谁的地址更大。
四、手写memcpy
memcpy和memmove的区别就在于,memmove可以防止内存覆盖,即源内存区域和目标内存区域有重叠的情况。而memcpy的话,需要我们手动保证内存不会有重叠,否则会产生未定义的行为。
# include<stdio.h>
# include<stddef.h>//包含size_t
//#include <iostream>
#include <string.h>
void *my_memcpy(void *destination,const void *sourse,size_t num);
int main()
{
char str[] = "this is an example";
printf("str的长度是: %d\n",strlen(str));//不包含'\0'结束符
printf("size_of str : %d\n",sizeof(str));//包含'\0'结束符
char des[30];
my_memcpy(des,str,strlen(str));
printf("str : %s\n",str);
printf("des : %s\n",str);
return 0;
}
void *my_memcpy(void *destination,const void *sourse,size_t num)
{
char* des = (char*)destination;
const char* src = (const char*)sourse;
for(size_t i = 0;i < num;i ++)
{
des[i] = src[i];
}
return destination;
}
在上面的代码中,我们之所以要将 void 类型指针转换为 char 类型指针,原因在于 void 类型不可知,无法对其进行解引用。
而我们要提取每个字节的值,然后逐个拷贝,最简单的就是找一个一个字节大小的数据类型,那么就是 char。