目录
前言:
介绍:
1.
2.strlen
3.strcpy
4.strcat
5.strcmp
6.strstr
模拟实现:
1.my_strlen
计数器:
指针:
递归:
2.my_strcpy
3.my_strcat
4.my_strcmp
5.my_strstr
总结:
本文主要以模拟实现库函数cstring中的部分字符串函数,包括:
“strlen”
“strcpy”
“strcat”
“strcmp”
“strstr”
翻译过来,就是一个头文件,定义包含了一些使用C 字符串和数组的函数。
以上就是头文件string.h的定义。
strlen简而言之就是统计字符串中‘\0’之前的元素个数。
相信大家已经对该函数有了一定了解,所以在此我们只是单单介绍,而重点在于模拟实现各个函数。
strcpy简而言之就是两个字符串的拷贝,将source里的字符数据拷贝到destination数组里,这里要注意的是,
拷贝也会把source数据里的‘\0’也拷贝进去。
必须要初始化两个数组。
并且保证destination足够大,且可以被修改。
切勿不可以使用char* destination = "abcd"这样子的常量字符串。
strcat函数简而言之是字符串追加函数,是将source里的元素(包括‘\0’)追加到destination里‘\0’的位置往后,意思就是会将source首元素与destination里的‘\0’替换开始,往后追加。
strcmp简而言之就是字符串比较函数,当str1中字符小于str2中的字符就返回-1,相等返回0,大于返回1。
要注意的是,这里我们是比较他们的ASCII码值。
strstr简而言之就是字符串查找函数,看看str1是否含有str2中的字符串,当存在时,就返回包含str2字符串加上后续内容的str1字符串。
以上就是我们将要模拟实现的字符串函数内容。
我们在实现my_strlen函数可以使用三种方法:
分别是,“计数器”,“指针”,“递归”
代码如下:
int my_strlen(const char* arr)
{
int count = 0;
while (*arr++)
{
count++;
}
return count;
}
int main()
{
char arr[] = "abcdef";
printf("%d\n", my_strlen(arr));
return 0;
}
计数器方法为最基础的内容,相信大家仅仅看代码就可以看明白
最终输出结果为
6
代码如下:
int my_strlen(const char* arr)
{
char* ret = arr;
while (*ret++)
{
;
}
return ret - arr - 1;
}
int main()
{
char arr[] = "abcdef";
printf("%d\n", my_strlen(arr));
return 0;
}
对于使用指针的方法解决,我们的具体操作是再创建一个指针ret,使ret对数组进行遍历操作,当ret指向‘\0’时,就停止,这样ret指向的‘\0’与首元素地址相差的值就是字符串元素个数了。
int my_strlen(const char* arr)
{
if (*arr == '\0')
{
return 0;
}
return 1 + my_strlen(arr + 1);
}
int main()
{
char arr[] = "abcdef";
printf("%d\n", my_strlen(arr));
return 0;
}
我们在学习递归的时候就会涉及该代码,在这里我不多进行赘述,看看代码就可以看懂。
代码如下:
#include
char* my_strcpy(char* dest, const char* src)
{
assert(dest && src);
char* ret = dest;
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char dest[] = "XXXXXXXXXXXXX";
char src[] = "hello";
printf("%s\n", my_strcpy(dest, src));
return 0;
}
在这里我们引入拓展了一个新知识点,assert
翻译过来再概括一下,就是assert为断言函数,它可以在调试的时候捕捉程序错误,我们目前只需知道这些就足够了,加上这一句可以使得代码风格更加健壮。
这里要注意的是,我们需要创建一个临时ret指针来帮助我们进行遍历,如果仅仅是单单移动dest指针,那这样经过后置++后指向的地址就不能恢复原状了。
输出结果为:
代码如下:
char* my_strcat(char* dest, const char* src)
{
char* ret = dest;
while (*dest != '\0')
{
dest++;
}
/*while (*dest++)
{
;
}*/ //不能写成这样,这样则会跳过‘\0’到下一个元素
while (*dest++ = *src++)
{
;
}
*dest = *src;
return ret;
}
int main()
{
char dest[20] = "abc";
char src[20] = "def";
printf("%s\n", my_strcat(dest, src));
return 0;
}
对于该函数的模拟,与strcpy相似,创建一个临时指针来进行遍历,但是这里我们才去的方法不一样的是:
如果用此while循环遍历时,当dest指向‘\0’时还会再进行一次++操作,这样我们就是将src中的元素追加到‘\0’后面了,即如图所示:
那这样存放数据就会变成下图:
这样当我们去访问dest时,打印遇到‘\0’就会停止了。
输出结果为:
int my_strcmp(const char* dest, const char* src)
{
while ((*dest != '\0') && (*src != '\0'))
{
if (*dest < *src)
{
return -1;
}
else if (*dest>*src)
{
return 1;
}
else
{
++dest;
++src;
}
}
if (*dest < *src)
{
return -1;
}
else if (*dest>*src)
{
return 1;
}
return 0;
}
int main()
{
char dest[] = "abcd";
char src[] = "abd";
printf("%d\n", my_strcmp(dest, src));
return 0;
}
本代码没有过多需要解释的,多看几遍代码就可以看懂,我们把重点放在下述的strstr中。
输出结果为:
#include
const char* my_strstr(const char* str1, const char* str2)
{
assert(str1 && str2);
if (*str2 == '\0'){ return str1; }
const char* p = str1;
const char* s1 = NULL;
const char* s2 = NULL;
while (*p)
{
s1 = p;
s2 = str2;
while (*s1 == *s2 && *s1 && *s2)
{
s1++;
s2++;
}
if (*s2 == '\0'){ return p; }
p++;
}
return NULL;
}
int main()
{
char str1[] = "abbcd";
char str2[] = "abc";
const char* ret = my_strstr(str1, str2);
if (ret == NULL)
{
printf("找不到\n");
}
else
{
printf("%s\n", ret);
}
return 0;
}
对于该函数的实现,我们用画图的方式来讲解容易理解些。
这里提前讲解下s1 、s2 、p分别代表什么。
s1为遍历str1的指针
s2为遍历str2的指针
p为记录开始匹配位置的指针
以上是我们第一次初始化的具体图示,
接下来我们进入while(*p)循环中
如图:
此时s1指向的位置与s2指向的位置不一致,所以p++。
这时候s1也进行++,
这是进入第二个while循环里,发现满足*s1 == *s2,所以s1和s2各自++,
此时不满足第二个while循环,所以跳出循环,p再++。
s2回到首元素地址处,
再次进入第二个循环,又发现*s1 == *s2,
又发现相等,继续循环,直到如图所示
此时*s2 == ‘\0’,return p指向的位置。
这样输出结果就是bcd。
如图:
以上代码是在string.h中模拟实现部分字符串函数,后续我会继续补充更多的内容。
记住
“坐而言不如起而行”
“Action spear louder than words”
具体的代码可以参考我的Gitee:
The_character_function_CSDN/The_character_function_CSDN/test.c · 无双/test_c_with_X1 - Gitee.com