手撕字符串函数,包括:
- memcpy
- memmove
- strcpy
- strcat
- strcmp
- strstr
memcpy
memcpy函数是c和c++使用的内存拷贝函数,
函数原型是:void memcpy(voiddest, const void *src, size_t n);
表示由src指向地址为起始地址的连续n个字节的数据复制到以dest指向地址为起始地址的空间内。与strcpy相比,memcpy并不是遇到’\0’就结束,而是一定会拷贝完n个字节。
注意事项:对于地址重叠的情况,上述函数的行为是未定义的,因此要考虑到此问题
要点:void*类型的指针不能运算,必须强转
void* memcpy(void *dst, const void *src, size_t size)
{
if (dst == nullptr || src == nullptr)
return nullptr;
char *temp_dst = (char*) dst;
char *temp_src = (char*) src;
if (temp_dst > temp_src && temp_dst < temp_src+size)
{
//内存重叠,自后向前拷贝
temp_dst = temp_dst+size-1;
temp_src = temp_src+size-1;
while (size--)
{
*temp_dst-- = *temp_src--;
}
}
else
{
//正常拷贝,从前往后
while (size--)
{
*temp_dst++ = *temp_src++;
}
}
return (void*) dst;
}
strcpy
strcpy 只能拷贝字符串,它遇到’\0’就结束拷贝。
char * strcpy(char* dst, const char* src)
{
if (dst == nullptr || src == nullptr)
return nullptr;
char* res = dst;
while (*dst != '\0')
{
*dst++ = *src++;
}
return res;
}
strcat
把 src 所指向的字符串追加到 dest 所指向的字符串的结尾。
char* strcat(char *dest,const char *src) {
//1. 将目的字符串的起始位置先保存,最后要返回它的头指针
//2. 先找到dest的结束位置,再把src拷⻉到dest中,记得在最后要加上'\0'
char *ret = dest;
assert(dest!= nullptr);
assert(src!= nullptr);
while(*dest!='\0')
dest++;
while(*src!='\0')
*(dest++)=*(src++);
*dest='\0';
return ret;
}
strcmp
把 str1 所指向的字符串和 str2 所指向的字符串进⾏⽐较。
//该函数返回值如下: |
strlen
获取字符串长度,通过起始地址和’\0’地址间隔判断
int strlen(const char *str) {
assert(str != NULL);
int len = 0;
while( (*str++) != '\0'){
len++;
}
return len;
}
strfind
在字符串 str1中查找第⼀次出现字符串 str2 的位置,不包含终⽌符 ‘\0’。
char* strstr(const char *str1, const char *str2) {
char* tmp_s = str1;
assert(str1 != nullptr);
assert(str2!= nullptr);
//若str2为空,则直接返回空
if(!str2){
return nullptr;
}
//若不为空,则进⾏查询
while(*tmp_s != '\0') {
char* s1 = tmp_s;
char* s2 = str2;
while(*s1 != '\0' && *s2!='\0' && *s1 == *s2){
s1++;
s2++;
}
//若s2先结束
if(*s2 == '\0'){
return str2;
}
//若s1先结束⽽s2还没结束,则返回空
if(*s2 != '\0' && *s1== '\0'){
return nullptr;
}
tmp_s++;
}
return nullptr;
}