🌈write in front :
🔍个人主页 : @啊森要自信的主页
✏️真正相信奇迹的家伙,本身和奇迹一样了不起啊!
欢迎大家关注🔍点赞👍收藏⭐️留言📝>希望看完我的文章对你有小小的帮助,如有错误,可以指出,让我们一起探讨学习交流,一起加油鸭。
文章目录
- 📝前言
- 🌠 库函数strcpy
- 🌉strcpy的模拟实现
- 🌠库函数strcat
- 🌉strcat的模拟实现
- 🌠strcmp 的使⽤
- 🌉strcmp 模拟实现
- 🌠 strstr 的使⽤
- 🌉strstr 的模拟实现
- 🚩总结
📝前言
记上节,我们学了字符串strlen
的使用和三种模拟实现方法,本小节,阿森继续和你一起学习4个字符串函数:strcpy
,strcat
,strcmp
,strstr
的使用和他的模拟实现方法,学习这些库函数,可以更好的方便操作字符和字符串,文章干货满满,接下来我们就学习一下这些函数吧!
🌠 库函数strcpy
strcpy
函数是将源字符串拷贝到目标字符串中,覆盖目标字符串原有内容。
char *strcpy(char *dest, const char *src);
dest:目标字符串,用于保存拷贝结果。
src:源字符串,将其内容拷贝到dest中。
返回值:返回目标字符串dest的指针。
注意点:
-
strcpy
函数会将src
字符串中的字符一个一个地复制到dest
字符串中,直到遇到字符串结束标志'\0'
为止。 -
src
字符串必须以'\0'
结束。 -
会将源字符串中的
'\0'
拷⻉到⽬标空间。 -
dest
字符串要有足够的空间,不然会导致缓冲区溢出。
-
目标空间必须是可修改的
代码:
int main()
{
char arr1[20] = "xxxxxxxxx";
char arr2[] = {'a', 'b', 'c','\0'};
strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
运行结果:
🌉strcpy的模拟实现
- 方法一
void my_strcpy(char* dest, char* src)
{
while (*src != '\0')
{
*dest = *src;
dest++;
src++;
}
*dest = *src;
}
int main()
{
char arr1[20] = { 0 };
char arr2[] = "abcdef";
my_strcpy(arr1, arr2);
printf("arr1 after copy: %s\n", arr1);
return 0;
}
分析: 使用
while
循环,循环条件是源字符串src
指针指向的字符不为'\0'
,每次循环体内,将src
指向字符复制到dest
指向位置,分别使dest
和src
指针后移,指向下一个字符位置,循环结束后,将字符串结束符'\0'
也复制到dest
指向位置
- 方法二
第一种方法缺陷太多了,比如没有返回值,无法知道拷贝是否成功。
char* my_strcpy(char* dest, const char* src)
{
assert(dest != NULL);
assert(src != NULL);
检查dest和src参数是否为NULL,NULL参数会导致访问异常。需要#include <assert.h>
char* ret = dest;
保存dest原始地址到ret变量,后面返回值使用。
assert(dest && src);
再次检查dest和src是否合法,防御性编程。
while (*dest++ = *src++)
{
;
}
return ret;
}
while (*dest++ = *src++)
先一次赋值dest
和src
当前字符(*dest = *src),然后并使指针后(dest=dest+1,src=src+1),while
循环结束条件是当src
字符串末尾'\0'
字符被复制时结束,当src
指向\0,
此时\0
赋值给*dest
,符合while
循环结束条件,跳出循环.
🌠库函数strcat
strcat
函数用于将源字符串src
追加到目标字符串dest
的结尾。
char *strcat(char *dest, const char *src);
dest - 目标字符串,必须有足够的空间存储追加后的结果字符串。
src - 源字符串。
返回值: 返回目标字符串dest的地址。
strcat
首先找到dest
字符串的结尾,即'\0'
字符的位置。从dest
字符串结尾开始,将src
字符串一个字符一个字符地复制过来。将src
字符串的结束'\0'
字符也复制到dest
后面。最后返回dest
地址。
关键点:
- 源字符串
src
必须以'\0'
结束。 - ⽬标字符串中也得有
\0
,否则没办法知道追加从哪⾥开始。 dest
必须有足够的空间存储追加后的结果字符串。- ⽬标空间必须可修改。
- 字符串⾃⼰可不可以给⾃⼰追加?
使用:
int main()
{
char str1[20] = "Hello ";
char str2[20] = "World";
char str3[40];
/* 复制str1到str3 */
strcpy(str3, str1);
/* 将str2追加到str3结尾 */
strcat(str3, str2);
printf("str3 = %s\n", str3);
return 0;
}
输出:
str3 = Hello World
🌉strcat的模拟实现
- strcat的模拟实现一
char* my_strcat(char* dest, const char* src)
{
char* ret = dest;
assert(dest && src);检查参数是否合法。
//1. 找到目标空间的\0
使用while循环找到dest字符串的结束'\0'字符,dest指针指向字符串结束后的位置。
while (*dest)
{
dest++;
}
//2. 拷贝
while (*dest++ = *src++)
{
;
}
return ret;
}
while (*dest++ = *src++)先一次赋值
dest
和src
当前字符(*dest = *src),然后并使指针后(dest=dest+1,src=src+1),先读取src
的一个字符将字符赋给dest
指向的位置,然后dest
和src
同时后移一个位置循环,当src
指向\0,
此时\0
赋值给*dest
,循环结束.
2.字符串⾃⼰可不可以给⾃⼰追加? 答案是:不能给自己追加。
char* my_strcat(char* dest, const char* src)
{
char* ret = dest;
assert(dest && src);
//1. 找到目标空间的\0
while (*dest)
{
dest++;
}
//2. 拷贝
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr1[20] = "hello";
my_strcat(arr1, arr1);
printf("%s\n", arr1);
return 0;
}
运行代码图:
🌠strcmp 的使⽤
strcmp
用于比较两个字符串是否相等,也就是比较字符串大小的函数。
函数原型:
int strcmp(const char *str1, const char *str2);
str1和str2是要比较的两个字符串指针。
strcmp
比较字符串的大小,不是按字符串的长度进行比较,而是逐个字符地比较两个字符串对应的每个字符的ASCII
码值。(比较使用的是无符号字符值的ASCII码顺序。)
-
返回值:
-
如果
str1
和str2
完全相等,返回0
。 -
如果s
tr1
大于str2
(按ASCII
码顺序),返回一个大于0
的数。 -
如果
str1
小于str2
,返回一个小于0
的数。
-
-
strcmp()
函数是C标准库string.h
头文件中的函数。 -
字符串比较结束条件是遇到字符串末尾
'\0'
字符或者第一个不匹配字符。
字符串"cat" 和 "dog" 的比较:
'c'的ASCII码是99, 'd'的ASCII码是100,所以"cat"小于"dog"
字符串"hello" 和 "hello world" 的比较:
前6个字符都相等,但第7个字符' '的ASCII码小于'\0',所以"hello"小于"hello world"
例子:
#include <string.h>
int main()
{
char str1[] = "ahbyb";
char str2[] = "asyzx";
int result = strcmp(str1, str2);
if(result == 0)
printf("Strings are equal\n");
else if(result > 0)
printf("str1 is greater than str2\n");
else
printf("str1 is less than str2\n");
return 0;
}
结果:
str1 is less than str2
🌉strcmp 模拟实现
int my_strcmp(const char* s1, const char* s2)
{
while (*s1 == *s2)
{
if (*s1 == '\0')
return 0;
s1++;
s2++;
}
return *s1 - *s2;
//if (*s1 > *s2)
// return 1;
//else
// return -1;
}
使用while
循环逐个比较s1
和s2
每个字符是否相等如果字符相等,继续循环比较下一个字符, 如果遇到字符串结束符’\0’,表示两个字符串完全匹配,直接返回0
,如果在循环中找到不匹配的字符,使用*s1 - *s2
返回两个字符的ASCII
码差值
🌠 strstr 的使⽤
strstr
用来查找一个字符串在另一个字符串中首次出现的位置。
strstr函数的原型:
char* strstr(const char* str1, const char* str2);
- str1: 主字符串,要在其中查找子字符串
- str2: 子字符串,要查找的字符串
strstr
函数可以用来在一个字符串中查找另一个字符串首次出现的位置,如果str2
不存在于str1
中,则返回NULL
;如果str2
存在于str1
中,则返回第一个匹配位置的指针。
strstr的比较原理是:
-
从
str1
字符串的起始位置开始,与str2
字符串进行字符匹配比较。 -
如果匹配失败(当前字符不同),则
str1
指针后移一位,继续匹配。 -
如果匹配成功(到达
str2
字符串结束符'\0'
),则匹配成功,返回str1
指针地址。 -
如果遍历完
str1
仍未匹配成功,则返回NULL
。
例如:
char* p = strstr("hello world","world");
// p指向"world"子字符串在"hello world"中的位置
这里用一个图来解释strstr函数的工作原理:
+----------------------+
str1 => | h e l l o w o r l d|
+----------------------+
|
V
+-----------+
str2 => | w o r l d |
+-----------+
|
V
比较第一个字符'h'与'w',不匹配
|
V
指针后移到下一个字符'e'
|
V
比较'e'与'w',不匹配
|
V
指针后移到下一个字符'l'
|
V
比较'l'与'w',不匹配
|
V
指针后移,依次比较直到匹配成功
|
V
当str1指针指向'w'时,与str2第一个字符'w'匹配
|
V
开始匹配后续字符,全部匹配成功
|
V
返回str1指针地址,指向子字符串在主字符串中的位置
int main()
{
char arr1[] = "abcegtbaab";
char arr2[] = "cegtba";
char* ret = strstr(arr1, arr2);
if (ret != NULL)
printf("%s\n", ret);
else
printf("找不到\n");
return 0;
}
结果:
cegtbaab
当然也可以用图展示:
strstr
从str1
起始位置开始,用str2
与str1
进行字符匹配比较。如果不匹配就后移str1
指针,匹配成功就返回str1
当前位置指针,上图就是返回c
的地址。通过这种逐个匹配的方式找到子字符串在主字符串中的第一个匹配位置。
🌉strstr 的模拟实现
char* my_strstr(const char* str1, const char* str2)
{
const char* cur = str1;//用cur记录str1的位置
const char* s1 = NULL;//使用assert检查str1和str2是否为非空指针。
const char* s2 = NULL;
assert(str1 && str2);
if (*str2 == '\0')//检查str2是否为空字符串,如果为空直接返回str1。
{
return (char*)str1;
}
while (*cur)//使用cur指针遍历str1。
{ //每次遍历:
s1 = cur;//将cur赋值给s1,将str2赋值给s2,用于后续匹配
s2 = str2;//当然,第几次失败后,重新回溯,重新开始匹配
while (*s1 && *s2 && *s1 == *s2)
{
s1++;//开始匹配s1和s2中的字符,同时递增s1和s2。
s2++;
}
if (*s2 == '\0')如果s1和s2匹配到结尾('\0'),表示找到了子串,返回cur。
{
return (char*)cur;
}
cur++;匹配失败后,cur++继续下次匹配。
}
return NULL;遍历完str1没有找到匹配,返回NULL。
}
时间复杂度为O(MN)
,其中M和N分别为主串和子串的长度。
若老铁们有点蒙蒙的,可以结合下图来理解:
🚩总结
这次阿森和你一起学习4个C语言中常用的基本字符操作函数,当然这只是一部分,还有很多,但阿森会慢慢和你一起学习。感谢你的收看,如果文章有错误,可以指出,我不胜感激,让我们一起学习交流,如果文章可以给你一个小小帮助,可以给博主点一个小小的赞😘