本文主要介绍一些C语言中常用字符串函数及部分函数的模拟实现。以下函数均需要包含头文件:
<string.h>。
目录
一、strlen函数
1.函数介绍
字符串以 '\0' 作为结束标志,strlen函数返回的实在字符串中 '\0' 前面出现的字符个数(不包含 '\0')。
注意点:
① 参数指向的字符串必须要以 '\0' 结束。
② 注意函数的返回值为size_t,是无符号的。(易错)
例题:下面代码的结果是?
#include <stdio.h>
int i;
int main()
{
i--;
if (i > sizeof(i))
{
printf(">\n");
}
else
{
printf("<\n");
}
return 0;
}
结果打印: >
解析:
C语言中,0为假,非0即为真。
全局变量,没有给初始值时,编译其会默认将其初始化为0。
i的初始值为0,i--结果-1,i为整形,sizeof(i)求i类型大小是4,按照此分析来看,结果应该选择B,但是sizeof的返回值类型实际为无符号整形,因此编译器会自动将左侧i自动转换为无符号整形的数据,-1对应的无符号整形是一个非常大的数字,超过4或者8,因此结果输出大于号。
代码演示:
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = "abcd";
int len = strlen(arr);
printf("%d\n", len);
return 0;
}
输出结果:4
2.strlen函数的模拟实现(三种方法)
1.计数器
思路:
我们定义一个计数器count,当指针指向的内容不为 '\0' 时,count+1即可,最后返回count。
size_t my_strlen(const char* str)
{
size_t count = 0;
while (*str)
{
count++;
str++;
}
return count;
}
2.递归
思路:
当指针指向的内容不为 '\0' 时,1+该函数并且把指针加1作为参数。指针指向的内容为 '\0'时,返回0。
size_t my_strlen(const char* str)
{
if (*str)
{
return 1 + my_strlen(str + 1);
}
else
{
return 0;
}
}
3.指针相减
思路:
两指针相减结果为两指针间的元素个数。所以只需找到指针该字符串 '\0' 的指针,与参数指针相减即可。
size_t my_strlen(const char* str)
{
char* p = str;
while (*p)
{
p++;
}
return p - str;
}
二、strcpy函数
1.函数介绍
把指针source所指向的字符串复制到指针destination。
注意点:
① 源字符串必须以 '\0' 结束。
② 会将源字符串中的 '\0' 拷贝到目标空间。
③ 目标空间必须足够大,以确保能存放源字符串。
④ 目标空间必须可变。
代码演示:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "abcdefgh";
char arr2[] = "***";
printf("%s\n", arr1);
strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
拷贝前:abcdefgh
拷贝后:***
2.strcpy函数的模拟实现
思路:
将src所指向的源字符串中的字符依次赋值到dest所指向的目标字符串,并返回目标字符串的起始地址。
char* my_strcpy(char* dest, const char* src)
{
char* p = dest;
while (*dest++ = *src++);
return p;
}
三、strcat函数
1.函数介绍
把source所指向的字符串追加到destination所指向的字符串的结尾。
注意点:
① 源字符串必须以 '\0' 结束。
② 目标空间必须有足够的大,能容纳下源字符串的内容。
③ 目标空间必须可修改。
④ 源字符串中的 '\0'会一并拷贝到目标空间,并删除源字符串中的 '\0'。
strcat函数为自己追加时,会将源字符串中的 '\0'覆盖。因此,strcat函数无法为自己追加。
代码演示:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20] = "abcd";
char arr2[] = "efg";
printf("%s\n", strcat(arr1, arr2));
return 0;
}
输出结果:abcdefg
2.strcat函数的模拟实现
思路:
先找到目标字符串 '\0'的位置,再在 '\0'处追加源字符串,并返回目标字符串的起始地址。
char* my_strcat(char* dest, char* src)
{
assert(dest, src);//确保两个字符串不为空指针
char* p = dest;
while (*p)
{
p++;
}
while (*p++ = *src++)
{
;
}
return dest;
}
四、strcmp函数
1.函数介绍
把str1所指向的字符串和str2所指向的字符串进行比较。
该函数会比较两个字符串对应字符的ASCII值,直至两字符串都为 '\0'。
返回值:
- 如果返回值小于 0,则表示 str1 小于 str2。
- 如果返回值大于 0,则表示 str1 大于 str2。
- 如果返回值等于 0,则表示 str1 等于 str2。
代码演示:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "abcd";
char arr2[] = "abfd";
printf("%d\n", strcmp(arr1, arr2));
return 0;
}
输入结果:-1 即字符串arr1 < arr2
2.strcmp函数的模拟实现
思路:
比较两个字符串对应字符的ASCII值,若两字符相等,则比较下一对字符。若两字符串长度相等,则两个字符都为 '\0'时,两字符串相等。若两字符串长度不等,且前面部分都相等,则返回其中一个字符与 '\0'的差值。
int my_strcmp(const char* p1, const char* p2)
{
assert(p1 && p2);//确保两指针不为空指针
while (*p1 == *p2)
{
if (*p1 == '\0')
{
return 0;
}
p1++;
p2++;
}
return *p1 - *p2;
}
五、strncpy函数
1.函数介绍
把source所指向的字符串复制到destination,最多复制num个字符。
注意点:
① 当source的长度小于 num 时,destination的剩余部分将用0填充。
其他部分与strcpy函数相同。
代码演示:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[10] = "abcdefg";
char arr2[] = "***";
printf("%s\n", strncpy(arr1, arr2, 4));
return 0;
}
输出结果:***
六、strncat函数
1.函数介绍
把source所指向的字符串追加到destination所指向的字符串的结尾,直到num字符长度为止。
注意点:
① 当源字符长度小于num时,只追加源字符串。
其他部分与strcat函数相同。
代码演示:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[10] = "abcdef";
char arr2[] = "****";
printf("%s\n", strncat(arr1, arr2, 3));
return 0;
}
输出结果:abcdef***
七、strncmp函数
1.函数介绍
把str1和str2进行比较,最多比较前num个字节。
注意点:
① 比较到出现另个字符不一样或者一个字符串结束或者num个字符全部比较完。
其他部分与strcmp函数相同。
代码演示:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "abcdefg";
char arr2[] = "abchijkl";
printf("%d\n", strncmp(arr1, arr2,3));
}
输出结果:0 只比较前3个字符时相等。
八、strstr函数
1.函数介绍
在字符串str1中查找第一次出现字符串str2的位置,不包含终止符 '\0'。
返回值:
返回在字符串str1中中第一次出现str2字符串的位置,如果未找到则返回null。
代码演示:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "abcdefgh";
char arr2[] = "cde";
printf("%s\n", strstr(arr1, arr2));
return 0;
}
输出结果:cdefgh
如果查找不到,则输出:(null)
2.strstr函数的模拟实现
思路:
将字符串str1与str2逐字符比较,并记录字符串str1当前字符的地址,如果不同,则str1+1再与str2逐字符比较,直到字符串str1当前字符为'\0'。
char* my_strstr(const char* s1, const char* s2)
{
assert(s1 && s2);//确保s1、s2不为空指针
char* cur = s1;
char* p1;
char* p2;
while (*cur)
{
p1 = cur;
p2 = s2;
while ( *p1 && *p2 && *p1 == *p2)
{
p1++;
p2++;
}
if (*p2 == '\0')
{
return cur;
}
cur++;
}
return NULL;
}
九、strtok函数
1.函数介绍
把字符串str分解为一组字符串,sep为分隔符。
注意点:
① sep参数是个字符串,定义了用作分隔符的字符集合。
② 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
③ strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注: strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容 并且可修改。)
④ strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
⑤ strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
⑥ 如果字符串中不存在更多的标记,则返回 NULL 指针。
代码演示:
#include<string.h>
#include <stdio.h>
int main()
{
char* p = "123456789@163.com";
const char* sep = "@.";
char arr[30];
char* str = NULL;
strcpy(arr, p);//将数据拷贝一份,处理arr数组的内容
str = strtok(arr, sep);
printf("%s\n", str);
str = strtok(NULL, sep);
printf("%s\n", str);
str = strtok(NULL, sep);
printf("%s\n", str);
return 0;
}
输出结果:
123456789
163
com
当分割段数增多时,代码则过于繁杂,所以用循环优化:
#include<string.h>
#include <stdio.h>
int main()
{
char* p = "123456789@163.com";
const char* sep = "@.";
char arr[30];
char* str = NULL;
strcpy(arr, p);//将数据拷贝一份,处理arr数组的内容
for (str = strtok(arr, sep); str != NULL; str = strtok(NULL, sep))
{
printf("%s\n", str);
}
return 0;
}
输出结果相同。
十、strerror函数
1.函数介绍
从内部数组中搜索错误号errnum,并返回一个指向错误信息字符串的指针。
代码演示:
#include<stdio.h>
#include<string.h>
#include<errno.h>//所需包含的头文件
int main()
{
printf("%s\n", strerror(errno));
return 0;
}
没有错误时:
输出结果:No error
#include<stdio.h>
#include<string.h>
#include<errno.h>//所需包含的头文件
int main()
{
FILE* pf;
pf = fopen("unexist.ent", "r");
if (pf == NULL)
printf("%s\n", strerror(errno));
return 0;
}
文件不存在时:
输出结果:No such file or directory(没有这样的文件或目录)