目录
- 模拟实现strlen
- 模拟实现strcpy
- 模拟实现strncpy
- 模拟实现strcat
- 模拟实现strncat
- 模拟实现strstr
- 模拟实现strcmp
- 模拟实现strncmp
- 模拟实现memcpy
- 模拟实现memmove
##1.模拟实现strlen函数
strlen是计算字符串长度的函数,不包含'\0',我们要模拟实现这个函数,方法不止一种,这里解释三种方法:方法一:计数器方式
int my_strlen(const char* arr)
{
assert(arr);
int count = 0;
while (*arr++)//遍历
{
count++;//计数
}
return count;
}
方法二:递归(不创建临时变量)
int my_strlen(const char* arr)
{
assert(arr);
if (*arr == '\0')
return 0;
else
return 1 + my_strlen(arr + 1);//根据递归的次数,每次加1
}
方法三:指针—指针
int my_strlen(const char* arr)
{
assert(arr);
char *p = arr;//先将起始位置存起来
while (*p != '\0')
{
p++;//遍历得到指向'\0'前面位置的指针
}
return p-arr;//后-前得到的是中间元素的个数
}
注:指针减指针得到的是中间元素的个数。
##2.模拟实现strcpy函数
strcpy函数是将源字符串拷贝到目标字符串里最优代码如下: ``` char *my_strcpy(char *dest, const char *src)//源字符串不能被改变 { assert(dest&&src);//保证两个指针的有效性 while (*dest++=*src++)//遇到'\0'停下来 { ;//先将src赋给dest,再让各自往后移动 } return dest; } ```
思路:我们要将源字符串拷贝到目标字符串里,必然要找到源字符串的起始位置,即src,然后赋给dest,接着让src向后移动,再给dest,这样依次让src往后移动,当然每次赋值完后相应的dest也要向后移动。
3.模拟实现strncpy函数
strncpy函数是将源字符串拷贝到目标字符串里 ,相比strcpy多了一个参数,拷贝个数有限制
char *my_strncpy(char *dest, char *src, size_t num)
{
char *p = dest;
assert(dest&&src);
while (num--&&*src)
{
*dest++ = *src++;
}
if (num > 0)
{
num = num + 1;
while (num--)
{
*dest++ = '\0'; //当src的大小小于num时,补'\0',直到补到num
}
}
return p;
}
4.模拟实现strcat函数
strcat函数是将源字符串连接在目标字符串后面
思路:首先我们需要找到目标字符串’\0‘前面的位置,其次找到目标字符串的首位置,最后将两个字符串连接
char *my_strcat(char *dest, const char*src)//源字符串不能被改变
{
assert(dest&&src);//指针不为空
while(*dest)
{
dest++;//找到目标字符串的最后一个位置
}
while(*dest++ = *src++)//
{
;//将目标字符串接在源字符串后面,源字符串和目标字符串分别向后移
}
return dest;返回目标字符串首地址
}
5.模拟实现strncat函数
strncat函数是将源字符串连接在目标字符串后面 ,它相比strcat多了一个参数,是限制连接的个数
思路:首先我们需要找到目标字符串’\0‘前面的位置,其次找到目标字符串的首位置,最后将两个字符串连接,连接完之后会在后面加上‘\0’
char *my_strncat(char *dest,const char *src, size_t num)
{
char *p = dest;
assert(dest&&src);
while (*dest)
{
dest++;
}
while (num--)
{//要连接的个数作为循环条件
*dest++ = *src++;
}
*dest = '\0';//最后加上'\0'
return p;
}
6.模拟实现strstr函数
strstr是在源字符串里查找子字符串
思路:首先我们应该让子字符串先不动,在源字符串里从前往后遍历找到和子字符串首元素相同的元素,然后让各自都向后移动在进行比较,若后面后不同,则将源字符串移到下一个和子字符串首元素相同的元素,再进行比较,直到找到相同的,若找到,则返回子字符串所在元字符串中的位置及源字符串后面的部分,若找不到则返回空指针。
代码如下:
char *my_strstr(const char *src, const char *subsrc)//保证源字符串和子字符串不能被改变
{
assert(src&&subsrc);//指针不为空
const char *cur = src;//先将源字符串首位置存起来
const char *s1 = cur;
const char *s2 = subsrc;
if (*subsrc == '\0')//如果子字符串为空,则不查找
return (char *)src;
while (*cur)
{
s1 = cur;
s2 = subsrc;
while (*s1&&*s2&&*s1==*s2)//两个相等,则各自向后移动,比较下一对是否相等
{
s1++;
s2++;
}
if (*s2 == '\0')
return (char *)cur;
cur++;//若没找到,源字符串向后移动
}
return NULL;
}
7.模拟实现strcmp函数
strcmp比较两个字符串的大小
思路:两个字符串从前向后依次比较,若ASCLL值相等,则继续向后比较,结果返回两个字符串的差值,即前大于后,返回正数,前等于后返回0,前小于后返回负数。
int my_strcmp(const char *s1, const char *s2)//两个字符串不能被改变
{
assert(s1&&s2);//指针不能为空
while (*s1 == *s2)
{
if (*s1 == '\0')
return 0;
s1++;//如果相等继续向后比较
s2++;
}
return *s1 - *s2;//返回差值
}
8.模拟实现strncmp函数
strncmp比较两个字符串的大小,相比strcmp有比较个数的限制,前大于后返回1,前等于后返回0,前小于后,返回-1。
``` int my_strncmp(const char *dest,const char *src, size_t num) { assert(dest&&src); while ((num--) && (*dest == *src)) { dest++; src++; } if ((*dest - *src) > 0) return 1; else if ((*dest - *src) < 0) return -1; else return 0; } ```
9.模拟实现memcpy函数
memcpy是从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中
思路:整体和strcpy思路相差无几,但是要注意的是strcpy只是拷贝字符串,而memcpy可以拷贝任意类型。
代码如下:
void* my_memcpy(void *dest, const void *src, size_t count)//count是指要拷贝的字节数
{//返回值、参数可以是任意类型
void *ret = dest;
assert(dest&&src);//指针不为空
while (count--)
{
*(char *)dest = *(char *)src;//这里要先转化成char*类型才可以进行运算,因为参数是void*类型
dest = (char *)dest + 1;//因为++的运算级别高,所以向后移动的时候不能直接写++
src = (char *)src + 1;
}
return ret;
}
注:source和destin所指的内存区域可能重叠,但是如果source和destin所指的内存区域重叠,那么这个函数并不能够确保source所在重叠区域在拷贝之前不被覆盖。
##10.模拟实现memmov函数
memmove用于从src拷贝count个字节到dest,如果目标区域和源区域有重叠的话,memmove能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中。
思路:memmov在memcpy的基础上更高了一级,因为memmov可以实现由重叠现象的内存拷贝
代码如下:
void *my_memmov(void *dest, const void *src, size_t count)//count表示要移动的字节数
{//返回值和参数类型可以是任意类型
void *ret = dest;//将目标字符串首地址存起来
assert(dest&&src);//指针不能为空
if (dest < src)//当目标字符串在源字符串的前面时,从前向后拷贝
{
while (count--)
{
*(char *)dest = *(char *)src;//这里依然是转化成char*类型才可以进行计算
dest = (char *)dest + 1;
src = (char *)src + 1;
}
}
else//如果目标字符串在源字符串首地址的后面,从后向前拷贝
{
src = (char *)src + count - 1;
dest = (char *)dest + count - 1;
while (count--)
{
*(char *)dest = *(char *)src;//这里依然是转化成char*类型才可以进行计算
dest = (char *)dest - 1;
src = (char *)src - 1;
}
}
return ret;
}