导言:
C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在
常量字符串中或者字符数组中。字符串常量适用于那些对它不做修改的字符串函数。不管怎么样,我们都需要掌握字符串函数的使用,并通过自实现来加深理解。
目录
正文:
一.strcmp的使用和自实现
1.strcmp的使用:
strcmp函数是C语言中的一个标准库函数,其原型为:
int strcmp(const char *str1, const char *str2);
该函数用于比较两个字符串str1和str2的大小关系,并返回一个整数值。返回值的含义如下:
- 若str1小于str2,则返回一个负数;
- 若str1等于str2,则返回0;
- 若str1大于str2,则返回一个正数。
在C语言中,strcmp函数通过比较两个字符串的ASCII码值来判断它们的大小关系。具体而言,strcmp函数会逐个比较两个字符串中对应位置的字符,直到遇到不相等的字符或者字符串的末尾。
比较的方式如下:
- 如果两个字符串的当前字符相等,则继续比较下一个字符,直到遇到不相等的字符或者字符串的末尾。
- 如果两个字符串的当前字符不相等,则返回两个字符的ASCII码值之差。
- 如果一个字符串已经遍历完而另一个字符串还有剩余字符,则较长的字符串被认为大于较短的字符串。
下面是一个使用strcmp函数的示例代码:
#include <stdio.h>
#include <string.h>
int main() {
char str1[] = "hello";
char str2[] = "world";
//strcmp需要头文件<string.h>
int result = strcmp(str1, str2);
if (result < 0) {
printf("str1小于str2\n");
}
else if (result == 0) {
printf("str1等于str2\n");
}
else {
printf("str1大于str2\n");
}
return 0;
}
运行结果如下:
2.strcmp的自实现:
该自实现函数的原理是通过逐个比较两个字符串中对应位置的字符,直到遇到不相等的字符或者字符串的末尾。返回值即为两个字符串第一个不相等字符的ASCII码值之差。函数声明我们可以写成这样:
int my_strcmp(const char* str1, const char* str2)
由于我们只是对两个字符串进行比较,不需要改变其值,所以最好还是用const修饰两个参数。
具体步骤:
我们只需通过循环来一边判断对应字符是否相等,一边对两个字符串进行遍历。在循环中做一个判断条件,如果对应字符一直相等而且遍历到了字符串末尾则说明相等,直接返回0。否则返回两个不相同字符的差。
下面是一段示例代码:
#include<stdio.h>
#include<assert.h>
int my_strcmp(const char* str1, const char* str2) {
//断言str1,str2不为空
assert(str1 && str2);
while (*str1 == *str2) {
//由于*str1==*str2,所以当一个字符串为末尾,另一个也一定是末尾
if (*str1 == '\0') {
return 0;
}
str1++;
str2++;
}
return *str1 - *str2;
}
int main() {
char arr1[] = "abc";
char arr2[] = "abc";
int ret = my_strcmp(arr1, arr2);
printf("%d", ret);
return 0;
}
运行结果如下:
了解strcmp函数的使用和自实现方法对于提高编程效率和理解字符串操作有着重要意义。通过自实现strcmp函数,我们可以更好地理解strcmp函数的底层实现原理,并且可以根据自己的需求进行相应的修改和扩展。
二.strcat的使用和自实现
1.strcat的使用:
strcat函数是C语言中的一个字符串操作函数,用于将一个字符串追加到另一个字符串的末尾。它的原型如下:
char *strcat(char *dest, const char *src);
dest
:指向目标字符串的指针。目标字符串是要将源字符串追加到其末尾的字符串。src
:指向源字符串的指针。源字符串是要追加到目标字符串末尾的字符串。
strcat
函数将源字符串的内容追加到目标字符串的末尾,并返回指向目标字符串的指针。在追加过程中,目标字符串的内容会被修改,源字符串的内容不会受到影响。
使用strcat时有几个注意事项:
1.指向源字符串必须以'\0' 结束,以确保字符串的正确终止。
2.目标空间必须有足够的大,能容纳下源字符串的内容,以避免缓冲区溢出的问题。
3.目标空间必须可修改。
下面是一个示例代码(vs会认为strcat不安全,可以加上下面代码的第一行来屏蔽这个错误信息):
#pragma warning(disable:4996)
#include<stdio.h>
#include<string.h>
int main() {
char arr1[20] = "abcd\0xxxxxx";
char arr2[] = "efghi";
//注意strcat会找到目标字符串的\0,同时会用源字符串覆盖掉目标字符串的\0
//并将源字符串添加到目标字符串后,再添加一个\0
printf("%s", strcat(arr1, arr2));
return 0;
}
运行结果如下:
可见strcat的功能还是比较强大的,在平常的使用也比较频繁,熟练使用这个函数也会极大提高我们的编程效率。
2.strcat的自实现:
该自实现函数的原理是通过找到目标字符串dest的末尾,并将源字符串src的内容逐个拷贝到目标字符串的末尾。最后,将目标字符串的末尾添加上字符串结束符'\0'。
函数的声明可以这样写:
char* my_strcat(char* dest, const char* src)
具体步骤:
由于要返回目标地址,所以可以先用一个char*pc的变量来保存dest的地址,在通过pc对字符串进行遍历,这样就防止了dest的位置发生改变。通过while循环先找到目标字符串的\0,再利用循环一边找源字符串的\0,一边将源字符串的内容添加到目标字符串中。
#include<stdio.h>
#include<assert.h>
char* my_strcat(char* dest, const char* src) {
char* pc = dest;
assert(dest && src);
while (*pc) {
pc++;
}
while (*pc++ = *src++) {}
return dest;
}
int main() {
char arr1[20] = "abcd\0xxxxxx";
char arr2[] = "efghi";
printf("%s", my_strcat(arr1, arr2));
return 0;
}
三.strstr的使用和自实现
1.strstr的使用:
strstr
函数是一个非常有用的字符串操作函数,用于在一个字符串中查找另一个字符串的第一次出现,函数的原型如下:
char *strstr(const char *str1, const char *str2);
- str1:待查找的字符串。这是一个以
const char*
类型传递的指针,指向要在其中进行查找的字符串。通常称之为"干草堆"。- str2:要查找的字符串。这也是一个以
const char*
类型传递的指针,指向要查找的目标字符串。通常称之为"针"。
使用的注意事项:
字符串的结尾:
str1
和str2参数都是以const char*
类型传递的指针,表示字符串的起始地址。这意味着在调用strstr
函数时,传递给它的字符串参数必须是以'\0'
结尾的C风格字符串。如果字符串没有以'\0'
结尾,strstr
函数可能会导致未定义的行为。区分大小写:
strstr
函数是区分大小写的,即它会将大写字母和小写字母视为不同的字符。如果需要进行不区分大小写的查找,可以使用strcasestr
函数。
下面是一个示例代码:
#include<stdio.h>
#include<string.h>
int main() {
char arr1[] = "abcd";
char arr2[] = "bc";
printf("%s", strstr(arr1, arr2));
return 0;
}
运行结果为:
可见strstr返回的是字符相同的第一个参数的地址,我们可以利用strstr找到匹配的位置并进行一些我们想做的其它操作。
2.strstr的自实现:
这个函数的实现原理是通过两个指针分别遍历str1和str2,逐个字符进行比较。当找到相等的子串时,返回子串的起始位置;否则,返回NULL
表示未找到。
具体步骤:
首先判断str2是否为空字符串,如果是,则直接返回str1,因为空字符串是任何字符串的子串。
然后进入循环遍历str1字符串,直到遍历到字符串的结尾(即遇到
'\0'
)为止。在每一次循环中,我们使用两个指针s1和s2,分别指向当前遍历的位置和str2字符串的起始位置。
使用一个内部循环,不断比较s1,s2指向的字符是否相等,以及是否已经遍历到了str2字符串的结尾(即遇到
'\0'
)。如果比较发现两个字符不相等,或者s2已经遍历到了str2字符串的结尾,那么说明当前位置不是str2的起始位置。我们将s1指针向后移动一位,继续下一次循环。
如果s2已经遍历到了str2字符串的结尾,那么说明在str1中找到了一个与str2相等的子串。我们返回当前的str1指针,即指向子串的起始位置。
如果遍历完整个str1字符串,都没有找到与str2相等的子串,那么说明str1中不包含str2,我们返回
NULL
表示未找到。
#include<stdio.h>
#include<assert.h>
char* my_strstr(char* str1, char* str2) {
char* s1 = str1;
char* pc = str1;
//断言str1,str2不为空
assert(str1&&str2);
if (!*str2) return str1;
while (*s1) {
char* s2 = str2;
//如果已经遇到末尾,则没有必要再进行循环
while (*s1 && *s2 && *s1 == *s2) {
s1++;
s2++;
}
if (!*s2)
return pc;
pc++;
s1 = pc;
}
return NULL;
}
int main() {
char arr1[] = "abcd";
char arr2[] = "bcd";
printf("%s", my_strstr(arr1, arr2));
return 0;
}
运行结果如下:
可以发现与使用库函数的结果是一致的,但需要注意的是,自定义实现的函数和标准库中的
strstr
函数可能存在一些差异,事实上,还有kmp算法可以优化代码,提升效率,有兴趣的小伙伴可以自己去学习以下,但通过这种自实现也能够提高我们对该函数的理解。
总结:
本文主要介绍了strcmp,strcat,strstr三个函数的使用和自实现,这三个函数都是对字符串进行操作,在平常的使用中,应该注意几者的区别和注意事项。熟练了解掌握这几个函数,对编程的效率也会有较大的提升,希望本文章对你有所帮助。