strlen
1.定义
这是只针对字符串的计数功能函数,它用来统计\0之前的字符个数,返回值为int
目前所学有三种方法可以实现该函数的模拟:1.循环计数方法 2.递归方法 3.指针运算方法
2.模拟实现
1.循环计数
int my_strlen(const char* a)
{
int count = 0;
while (*a != 0)
{
count++;
a++;
}
return count;
}
2.递归
int my_strlen(const char* str)
{
if (*str != '\0')
{
return 1 + my_strlen(str + 1);
}
else if (*str == '\0')
{
return 0;
}
}
3.指针运算
int my_strlen(const char* str)
{
char* ret = str;
while (*str != '\0')
{
str++;
}
return str - ret;
}
3.区别strlen与sizeof
strlen是函数,而sizeof是操作符
sizeof统计的是目标所在的空间大小,而strlen只统计字符个数
sizeof可以计算整型数组,字符串,结构体等空间,而strlen只能计算字符串4
strcpy
1.定义
将来源字符串拷贝到目标字符串的后面,将目标字符串的\0变为来源字符串的首字符,并将来源字符串结尾的\0也拷贝到目标字符串中。返回目标字符串的首地址
2.模拟实现
char* my_strcpy( char* des,const char* src)
{
char* ret = des;
assert(des && src);
while (*src!='\0')
{
*des++=*src++;
}
return ret;
}
strcat
1.定义
这个函数的功能是给目标字符串的第一个\0处追加一个来源字符串。来源字符串的第一个\0同样被追加过去。
2.模拟实现
char* my_strcat(char* des, const char* src)
{
char* ret = des;
while (*des != '\0')
{
des++;//找到目标字符串的第一个'\0'
}
while (*src != '\0')
{
*des ++= *src++;
}
*des++ = *src++;
return ret;
}
3.同一字符串不能自我追加
![](https://i-blog.csdnimg.cn/blog_migrate/6f721c5e9385c51bc4cb30bc8b9a8fb6.png)
因为将来源字符串的第一个字符赋给目标字符串的\0时,由于目标和来源是同一个字符串,其实把来源字符串的\0覆盖了,导致该函数无法找到来源字符串的\0以结束
strstr
1.定义
这个函数的功能是在一个大字符串中找到含有小字符串的部分,并返回这部分的初始指针。
2.模拟实现
char* my_strstr(const char* des, const char* src)
{
char* s1 = des;
char* s2 = src;
char* s3 = s1;//s3是作为初始位置的一个记录
while (s1!='\0')
{
if (*s1 == *s2)
{
s1++;
s2++;
if (*s2 == '\0')//当来源字符串都找完了,还没有跳出,说明找到了
{
return s3;
}
}
else if (*s1 != *s2)
{
s1 = s3 + 1;//将下次开始寻找的初始位置回退到上次开始寻找的位置的下一位
s2 = src;//来源字符串的指针每次重新寻找都要回退到首字符
s3++;//s3作为s1的记录自然也要进到下一位
}
}
return NULL;
}
5.strtok
char* strtok(char* str,const char* sep)
1.定义
sep是使用者想要定义作为分割符的字符合集。
strtok会将来源字符串切分成一段一段的,会破坏原有的字符串,所以最好先将原有字符串进行拷贝。
如果第一个参数不为NULL,strtok会从参数的头部开始找到第一个标记,并返回切分的字符串地址,同时,strtok函数会在内部保存标记的地址;当strtok第一个参数为NULL时,strtok函数会从同一字符串被保存的位置开始查找下一个标记。
2.使用
int main()
{
char s[] = "1209722997@qq.com.cn";
char copy[30] = { 0 };
my_copy(copy, s);
char* str = NULL;
const char sep[] = "@.";
for (str = strtok(copy, sep); str != NULL;str= strtok(NULL, sep))
{
printf("%s\n", str);
}
return 0;
}
![](https://i-blog.csdnimg.cn/blog_migrate/e6a4b1351db430212e8ca7fbf2d29ac5.png)
3.注意
这个函数有记忆保存功能,即使在使用结束后,它还会保存上一次使用的时候,找到的标记的位置
6.内存函数memcpy memmove
定义
void* memmove(void* destination, const void* source, size_t num)
memcpy和memmove功能类似,这里主要学习memmove
这个函数的功能是将源内存块向后的num个字节复制到目标内存块中。memcpy 和memmove的区别是memmove的源内存块和目标内存块是可以重叠的
由于是以字节为单位复制,且不知道要移动的数据是什么类型的数据,所以形参定义为void* 类型,方便接收各种类型的数据,也方便转换为char* 类型
模拟实现
![](https://i-blog.csdnimg.cn/blog_migrate/09c695af364e88ac8681d81c38c1726d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6588b5776f95bd95eb669714174d45ad.png)
总体思路就是先将重叠部分的字节拷贝,防止被覆盖。这个思路决定从前向后或是从后向前的拷贝顺序。
void my_memmove(void* des, const void* src, size_t n)
{
if (src < des)
{
while (n--)
{
*((char*)des+n) = *((char*)src+n);
}
}
else if (des < src)
{
while (n--)
{
*(char*)des = *(char*)src;
des = (char*)des + 1;
src = (char*)src + 1;
}
}
}
7.memcmp
定义
int memcmp(const void* ptr1,const void* ptr1,size_t num)
比较ptr1和ptr2指针开始的num个字节
2.模拟实现
int my_memcmp(const void* p1, const void* p2, size_t n)
{
assert(p1 && p2);
while (*(char*)p1 == *(char*)p2)
{
p1 = (char*)p1 + 1;
p2 = (char*)p2 + 1;
}
return *(char*)p1 - *(char*)p2;
}
3.注意事项
由于是以字节为单位进行比较,所以根据大小端存储的不同,结果可能会不同
![](https://i-blog.csdnimg.cn/blog_migrate/169c8472ec33c228bbd0b0d64ea72cf0.png)