【C语言库函数】各字符串函数的使用和模拟实现
1、strlen
1.1、使用方法
strlen这个函数想必大家都不陌生,它的功能顾名思义就是求一个字符串的长度,使用的时候只需要传递一个字符串就可,我们在cplusplus上搜一下这个函数:
就能看到这样的描述。下面的那一大串英文描述我们可以不管,我们就看一下它的返回值类型,竟然是size_t——无符号整型。这样的设计其实是考虑到一个字符串的长度必定是大于零的,但这样设计也会导致一个有点儿“诡异”的状况:
这里明明是小于,却打印了大于,这是因为两个size_t进行计算,其最终结果一定也是size_t类型,即一定大于0。
所以关于这点我,们以后在使用需要特别注意如果要对两个字符串的长度进行相减操作的话最好先将各长度强制转换成int类型或保存在int类型变量里。例如:
1.2、模拟实现
思路分析:
strlen的实现原理很简单,就是统计一个字符串在遇到字符串结束标志‘\0’之前有多少个字符,最终返回统计到的字符个数即可。
模拟实现:
首先是一个最简单的实现方式,计数器:
int my_strlen1(const char* str) {
assert(str);
int count = 0;
while (*str++) {
count++;
}
return count;
}
在我们学了指针之后,我们知道指针减去指针表示指针之间的元素的个数。所以我们也就有了第二种实现方式,指针减指针:
int my_strlen2(const char* str) {
assert(str);
const char* temp = str;
while (*temp) {
temp++;
}
return temp - str;
}
但有些题目可能要求你不能创建临时变量,这时候就应该用到递归了,所以第三种实现方式递归法也就出来喽:
int my_strlen3(const char* str) {
assert(str);
if ('\0' == *str) {
return 0;
}
else {
return 1 + my_strlen3(str + 1);
}
}
2、strcpy和ctrncpy
2.1、使用方法
strcpy的功能就是将一个字符串的内容(包括其末尾的‘\0’)拷贝到另一个字符串中去,二strncpy则比它多出了个n,这个n表示的是要拷贝的字符的个数。例如我们现在有两个字符串:
char str1[] = "overtime!";
char str2[] = "no overtime!";
我们若想把str1拷贝到str2里,就可以使用strcpy:
若是我们想吧str1的所有内容都拷贝,而只想拷贝前4个字符,那我们就可以用strncpy:
2.2、模拟实现
在模拟之前,我们先看看这两个函数的描述信息:
划红线的地方是对这两个函数是否拷贝‘\0’的说明。其中strcp是不管三七二十一都是要拷贝‘\0’的,但strncpy只是在源字符串的长度小于要拷贝的字符个数是菜在后面追加‘\0’,一直追加到拷贝的字符数等于num为止。
模拟实现:
strcpy:
char* my_strcpy(char* dest, const char* src) {
assert(dest && src);
char* start = dest;
while (*dest++ = *src++) {
;
}
return start;
}
strncpy:
char* my_strncpy(char* dest, const char* src, int num) {
assert(dest && src);
char* start = dest;
while (num-- && (*dest++ = *src++)) {
;
}
if (0 == num) {
;
}
else {
while (num-- > 0) {
*dest++ = '\0';
}
}
return start;
}
3、strcat和strncat
3.1、使用方法
strcat的作用就是在一个字符串后面追加(连接)另一个字符串,而strncat也是和上面的一样表示只是具体连接几个字符,而并不是连接整个字符串。
比如我们现在有这两个字符串:
char str1[20] = "Salary";
char str2[] = " increase!!";
我们就可以利用strcat将str2连接到str1后面去:
我们也可以使用strncat来只追加一个字符:
3.2、模拟实现
在模拟实现之前,我们先看看这两个函数的描述:
通过描述我们可知两个函数在追加结束的时候都要加上一个字符串结束标志‘\0’,且strncat最多只追加到原字符串的结尾。
其实我们在找到目标字符串的第一个‘\0’的时候,只需要重复strcpy的操作即可,但是要注意strncat最多只追加到原字符串的末尾。
模拟实现:
strcat:
char* my_strcat(char* dest, const char* src) {
assert(dest && src);
char* start = dest;
// 先找到的dest的第一个'\0'
while (*dest) {
dest++;
}
// 然后重复strcpy的操作即可
while (*dest++ = *src++) {
;
}
return start;
}
strncat:
char* my_strncat(char* dest, const char* src, int num) {
assert(dest && src);
char* start = dest;
// 先找到的dest的第一个'\0'
while (*dest) {
dest++;
}
// 然后重复strncpy的操作即可
while (num-- && (*dest++ = *src++)) {
;
}
dest = '\0'; // 只追加到src的结尾
return start;
}
4、strcmp和strncmp
4.1、使用方法
strcmp的功能就是比较两个字符串的大小,如果两个字符串相等则返回0,不相等则返回其他数。比较的方法是逐个字母的比较如果当前比较的两个字母相等,则跳到下一个子母,若不相等,则这直接返回一个大于零或小于零的数。
strcmp是最多会比较到两个字符串的末尾,而strncmp是最多只比较n个字符。
比如说我们现在有两个字符串:
char str1[] = "str";
char str2[] = "string";
我们可以通过strcmp来比较这两个字符串是否相等:
也可以用strncmp来只比较他们前三个字符是否相同:
4.2、模拟实现
这两个函数的返回值应该都满足以下表格:
而且我们知道字符本质就是一个ASCII码值,所以我们找到两个不相等的字符后,直接返回它们的差即可。
这两个函数的模拟方式其实很简单,我这里就直接上代码了:
模拟实现:
strcmp:
int my_strcmp(const char* str1, const char* str2) {
assert(str1 && str2);
while ((*str1 == *str2) && (*str1 && *str2)) {
str1++;
str2++;
}
return *str1 - *str2;
}
strncmp:
int my_strncmp(const char* str1, const char* str2, int num) {
assert(str1 && str2);
int i = 0;
for (i = 0; i < num; i++) {
if (*(str1 + i) != *(str2 + i)) {
return *(str1 + i) - *(str2 + i);
}
}
return *(str1 + i - 1) - *(str2 + i - 1);
}
5、strstr
5.1、使用方法
strstr的功能就是求一个字符串是否是另一个字符串的字串,如果是就返回一个指向子串出现的第一个位置的指针,比如“ab”是“aab”的字串,将他们两个传入strstr返回的就应该是一个指向“aab”中第二个a指针,如果不是则返回空指针。
比如说我们现在有两个字符串:
char str1[] = "bab";
char str2[] = "aaababbbb";
我们可以使用strstr来判断一下str1是否为str2的子串:
我们可以看到,它返回的应该是一个指向第四个字符b的指针。
5.2、模拟实现
虽然子串匹配的算法有很多,但今天我给大家介绍的是一个最简单的方法——朴素法:
char* my_strstr(const char* str1, const char* str2) {
assert(str1 && str2);
const char* temp = str1; // 在外层遍历str1,找到有一个*str2就停下
const char* s1 = NULL; // 当temp找到一个*str2之后s1继续遍历temp后面的字符,判断子串
const char* s2 = NULL; // 当temp找到一个*str2之后s2继续遍历str2后面的字符,判断子串
while (*temp) {
while ((*temp != *str2) && *temp) {
temp++;
}
s1 = temp;
s2 = str2;
while ((*s1 == *s2) && (*s1 && *s2)) {
s1++;
s2++;
}
if ('\0' == *s2) {
return (char*)temp;
}
else {
temp++;
}
}
return NULL;
}