一.引言
在 C 语言编程中,字符串操作是最基础也最常用的功能之一。标准库提供的字符串函数如strcmp、strcpy、strcat和strstr极大地简化了我们的开发工作。但要真正掌握这些函数,理解其底层实现原理至关重要。本文将详细讲解这四个常用字符串函数的工作原理,并通过模拟实现帮助你深入理解它们的内部机制。
二.字符串复制函数:strcpy
函数原型:
char *strcpy(char *dest, const char *src);
功能说明:
①将src指向的字符串复制到dest指向的字符数组
②复制包括结束符\0
③要求dest必须有足够的空间容纳src字符串
④目标空间dest必须可修改
这里必须可修改指的是目标空间不能字符串字面量,例如char *p = "hello",字符串字面量作为一个字符常量是不允许被修改的!
//模拟实现
char* my_strcpy(char* dest, const char* src)
{
assert(dest && src); // 确保指针有效性
char* ret = dest; // 保存目标字符串起始地址
while (*dest++ = *src++) // 逐个复制字符
{
; // 空语句,循环体已在条件中完成
}
return ret; // 返回目标字符串起始地址
}
在这里,用ret变量保存dest的初始地址,以便最后返回。循环中先将*src赋值给*dest,然后两个指针都向后移动。当src指向\0时,赋值后表达式结果为 0,循环结束。
三.字符串拼接函数:strcat
函数原型:
char *strcat(char *dest, const char *src);
功能说明:
①将src指向的字符串追加到dest指向的字符串后面
②src必须\0结尾
③会覆盖dest原来的结束符\0,并在追加完成后添加新的\0
④要求dest必须有足够的空间容纳两个字符串的内容
⑤目标空间dest必须可修改
//模拟实现
char* my_strcat(char* dest, const char* src)
{
assert(dest && src); // 确保指针有效性
char* ret = dest; // 保存目标字符串起始地址
// 移动到目标字符串的末尾
while (*dest)
{
dest++;
}
// 追加源字符串
while (*dest++ = *src++)
{
; // 空语句,循环体已在条件中完成
}
return ret; // 返回目标字符串起始地址
}
在这里,第一个while循环将dest指针移动到目标字符串的\0位置。第二个while循环与strcpy的实现类似,将src的内容复制到dest末尾。最后,返回dest的初始地址。
需要特别提醒大家的一点是,strcat不能用于将字符串追加到自身,因为这会覆盖还未复制的内容。如:char arr[20] = "hello"; strcat(arr,arr); 注意这是错误示范,不要这样做!
四.字符串比较函数:strcmp
函数原型:
int strcmp(const char *str1, const char *str2);
功能说明:
①若第⼀个字符串大于第⼆个字符串,则返回大于0的数字。
②若第⼀个字符串等于第⼆个字符串,则返回0。
③第⼀个字符串小于第⼆个字符串,则返回小于0的数字。
//模拟实现
int my_strcmp(const char* str1, const char* str2)
{
assert(str1 && str2); // 确保指针有效性
while (*str1 == *str2) // 逐个字符比较
{
if (*str1 == '\0') // 同时到达结束符,字符串相等
{
return 0;
}
str1++; // 指针后移,比较下一个字符
str2++;
}
return *str1 - *str2; // 返回差值
}
在这里,使用assert确保传入的指针不为空,增强代码健壮性使用assert确保传入的指针不为空,增强代码健壮性。通过while循环逐个比较字符,当字符相等时移动指针继续比较。遇到不同字符时返回它们的 ASCII 值差值;若同时到达\0则返回 0。
五.字符串查找函数:strstr
函数原型:
char *strstr(const char *str1, const char *str2);
功能说明:
①在str1中查找str2第一次出现的位置
②若找到,返回str1中匹配的起始地址
③若未找到,返回NULL
④若str2是空字符串,则返回str1
//模拟实现
char* my_strstr(const char* str1, const char* str2)
{
assert(str1 && str2);
const char* cp = str1; // 用于遍历主串
// 若子串为空,返回主串起始地址
if (*str2 == '\0')
{
return ((char*)str1);
}
// 遍历主串
while (*cp)
{
const char* s1 = cp; // 主串当前比较位置
const char* s2 = str2; // 子串当前比较位置
// 比较字符,直到不匹配或任一字符串结束
while ((*s1 != '\0') && (*s2 != '\0') && (*s1 == *s2))
{
s1++;
s2++;
}
// 若子串已全部匹配,返回当前起始位置
if (*s2 == '\0')
{
return (char*)cp;
}
cp++; // 移动主串起始比较位置
}
return NULL; // 未找到匹配的子串
}
特殊情况处理:若子串为空,直接返回主串起始地址。双重循环结构:外层循环:cp指针遍历主串,标记每次比较的起始位置;内层循环:从cp位置开始,比较主串和子串的字符。匹配判断:当子串指针s2到达\0时,表示完全匹配,返回当前cp位置。
以上就是对 C 语言中 strcmp、strcpy、strcat 和 strstr 这几个常用字符串函数模拟实现的详细解析。从函数的核心逻辑到具体代码细节,我们不难发现指针操作和对字符串结束符 \0 的处理是实现这些功能的关键。 理解这些函数的底层实现,不仅能帮助我们更灵活地运用它们,也能加深对 C 语言字符串特性的认知。
如果你对这些函数的实现有不同的思路,或者在学习过程中遇到了相关问题,欢迎在评论区留言讨论,让我们一起交流进步!