目录
前言
C语言本身是没有字符串类型的,字符串通常放在字符数组或常量字符串中。本篇文章带大家看看C语言中对字符串处理的字符串函数。
本文所提出的函数均包含在string.h头文件中
(一)长度不受限的字符串函数
1.strlen
size_t strlen ( const char * str );
功能:获取一个字符串的长度
strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包含 ‘\0’ )。
实现方式:通过传字符串首元素地址遍历字符串,遇到’\0’停止,指针每走一次,加加一次。
使用示例:
复现思路:我们根据官方的参数列表写
返回值为size_t,是无符号的
size_t strlen ( const char * str );
计数器法:
我们可以创建一个计数器,用while循环遍历字符串,指针每走一次,计数器加一,直到遇到’\0’,循环结束,返回计数器数值。
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>
#include<string.h>
//创建my_strlen函数
int my_strlen(const char* str)
{
//断言,不传空指针
assert(str);
//创建计数器
int count = 0;
while (*str)
{
count++;
str++;
}
return count;
}
//测试
int main()
{
char arr[10] = "12345";
printf("%u\n", my_strlen(arr));
return 0;
}
指针减指针:
我们也可以设计一个头指针,用另一个指针遍历,最后两个指针相减得到的是指针间的元素个数
int my_strlen(char* s)
{
//断言,不传空指针
assert(s);
//创建一个头指针
char* p = s;
//用p指针遍历字符串
while (*p)
p++;
return p - s;
}
//测试
int main()
{
char arr[10] = "12345";
printf("%u\n", my_strlen(arr));
return 0;
}
2.strcpy
char * strcpy ( char * destination, const char * source );
功能:将源指针指向的字符串的所有内容拷贝到目标指针指向的空间(包括’\0’) 。
实现方式:传入目标空间和源字符串的首地址,将源字符串内容依次拷贝目标空间中,最后返回目标空间首地址。
注意事项:
- 源字符串必须以 ‘\0’ 结束。
- 目标空间必须足够大,以确保能存放源字符串。
- 目标空间必须可变。
使用示例:
复现思路:我们根据官方的参数列表写
char * strcpy ( char * destination, const char * source );
目标空间必须可变所以不能用const修饰,但我们不修改源字符串,为了防止源字符串被修改,加上const修饰
遍历源字符串,把源字符串的内容赋给目标空间,一直到把’\0’也赋给目标空间,最后返回修改后的字符串首地址。
char* my_strcpy(char* dest, char* src)
{
//先记录目标空间首地址,因为最后dest并不在首元素地址处
char* ret = dest;
//断言,不传空指针
assert(dest && src);
//*dest++的值为*dest,循环一次结束后dest加1
//src遇到'\0'后赋值'\0'地址给dest,使*dest为'\0',结束循环
while (*dest++ = *src++)
{
;
}
return ret;
}
//测试
int main()
{
char arr1[10] = "12345";
char arr2[10] = "67890";
printf("%s\n", arr1);
printf("%s\n", my_strcpy(arr1, arr2));
return 0;
}
3.strcat
char * strcat ( char * destination, const char * source );
功能:在一个字符串后追加另一个字符串内容。
实现方式:传入目标字符串和源字符串的首地址,将目标字符串遍历到’\0’,然后把源字符串内容赋到目标字符串后。
注意事项:
- 源字符串必须以 ‘\0’ 结束。
- 目标空间必须足够大,能容纳下源字符串的内容。
- 目标空间必须可修改。
- 字符串能自己给自己追加。
使用实例:
复现思路:我们根据官方的参数列表写
char * strcat ( char * destination, const char * source );
我们可以理解为strlen和strcpy函数的结合
char* my_strcat(char* dest, const char* src)
{
char* ret = dest;
assert(dest && src);
while (*dest)
{
dest++;
}
while (*dest++ = *src++)
{
;
}
return ret;
}
//测试
int main()
{
char arr1[20] = "12345";
char arr2[] = "67890";
printf("%s\n", arr1);
printf("%s\n", my_strcat(arr1, arr2));
return 0;
}
4.strcmp
int strcmp ( const char * str1, const char * str2 );
功能:比较两个字符串
- 第一个字符串大于第二个字符串,则返回大于0的数字
- 第一个字符串等于第二个字符串,则返回0
- 第一个字符串小于第二个字符串,则返回小于0的数字
字符串比较方式:
从比较两个字符串的首元素开始,若相同则继续比较下一个,直到字符不同或遇到’\0’。(比较的是字符的ASCII码值)。
字符不同时,
比较两字符的ASCII码值,若第一对不匹配的字符在str1中的值大于str2中的值则返回负数,两个字符串内容相同则返回0,第一对不匹配的字符在str1中的值小于str2中的值则返回正数(在VS平台上前大与后就返回1,后大于前就返回-1,相同返回0,不同平台实现方式不同)。
实现方式:通过两个字符串指针对两个字符串进行遍历,依次比较。
使用示例:
复现思路:我们根据官方的参数列表写
int strcmp ( const char * str1, const char * str2 );
对两个字符串进行遍历,依次比较
//进行比较不需要修改字符串,用const修饰
int my_strcmp(const char* str1, const char* str2)
{
//断言,不传空指针
assert(str1 && str2);
//当字符不同时结束循环
while (*str1 == *str2)
{
//进入该循环,一个字符串遍历到了'\0',则说明两个字符串已经比较到最后了,两个字符串相等
if (*str1 == '\0')
return 0;
str1++;
str2++;
}
return (*str1 - *str2);
}
//测试
int main()
{
char arr1[20] = "aaa";
char arr2[] = "aap";
int ret = my_strcmp(arr1, arr2);
if (ret > 0)
{
printf("str1大于str2\n");
}
else if (ret < 0)
{
printf("str1小于str2\n");
}
else
{
printf("str1等于str2\n");
}
return 0;
}
(二)长度受限制的字符串函数
1.strncpy
char * strncpy ( char * destination, const char * source, size_t num );
功能:从源字符串拷贝num个字符到目标空间。
如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。
使用示例:
复现思路:与strcpy函数一样,只是多了一个参数num,指复制num个字符(包括’\0’)。
代码:
char* my_strncpy(char* dest, const char* src, size_t num)
{
char* ret = dest;
assert(dest && src);
for (int i = 0; i < num; i++)
{
*dest++ = *src++;
}
return ret;
}
int main()
{
char arr1[14] = "xxxxxxxxx";
char arr2[] = "1234";
printf("%s\n", my_strncpy(arr1, arr2, 6));
return 0;
}
2.strncat
char * strncat ( char * destination, const char * source, size_t num );
功能:与strcat一样,只是多了一个参数num,指追加num个源字符串内容到目标字符串中。
若源字符串长度小于num,则仅复制’\0’之前的内容。
使用实例:
复现思路代码:
char* my_strncat(char* dest, const char* src, size_t num)
{
char* ret = dest;
assert(dest && src);
while (*dest)
{
dest++;
}
for (int i = 0; i < num; i++)
{
*dest++ = *src++;
}
return ret;
}
//测试
int main()
{
char arr1[13] = "hello ";
char arr2[6] = "world";
printf("%s\n", my_strncat(arr1, arr2, 5));
return 0;
}
3.strncmp
int strncmp ( const char * str1, const char * str2, size_t num );
功能:与strcmp一样,只是多了一个参数num,指比较num个。
使用示例:
复现代码:
int my_strncmp(const char* str1, const char* str2, size_t num)
{
assert(str1 && str2);
for (int i = 0; i < num; i++)
{
if (*str1 != *str2)
return (*str1 - *str2);
str1++;
str2++;
}
return 0;
}
//测试
int main()
{
char arr1[20] = "aaa";
char arr2[] = "aap";
int ret = my_strncmp(arr1, arr2, 3);
if (ret > 0)
{
printf("str1大于str2\n");
}
else if (ret < 0)
{
printf("str1小于str2\n");
}
else
{
printf("str1等于str2\n");
}
return 0;
}
(三)字符串查找函数
1.strstr
char * strstr ( const char *str1, const char * str2);
功能:在str1字符串中找str2(待查找的字符串)字符串。
即查找子字符串
实现思路:
1.先从头遍历str1,若找到了与str2首字符相同的字符,则创建一个指针cp用来记录这个位置,再从这个位置向后开始依次比较。
2.创建s1,s2两个指针,用来遍历比较,若s1一直等于s2,s2能一直走直到找到’\0’,则说明在str1找到了str2这个字符串,返回第一个相同字符的地址(cp),否则就返回NULL。
3.若遍历比较中有不同,则s1,s2停止遍历,cp向前走一步(cp++),s1复位到此时cp的这个位置(s1=cp),s2再次复位到首地址(s2=str2),重复步骤2,直到s2找到’\0’。
使用示例:
复现代码:
char* my_strstr(const char* str1, const char* str2)
{
char* s1 = str1;
char* s2 = str2;
char* cp = str1;
//因为str1中总含有'\0'
//故*str2 == '\0'时直接返回
if (*str2 == '\0')
return str1;
while (*cp)
{
//复位
s1 = cp;
s2 = str2;
//若两字符串指针都没有走到'\0',
//且两字符串指针所指向的字符相等
//则进行比较遍历
while (s1 && s2 && *s1 == *s2)
{
s1++;
s2++;
}
//若待查找字符串指针走到'\0',返回cp
if (*s2 == '\0')
return cp;
cp++;
}
}
int main()
{
char arr1[20] = "helhello";
char arr2[20] = "hello";
char* ret = my_strstr(arr1, arr2);
if (ret != NULL)
printf("找到了\n");
else
printf("没找到\n");
printf("%s\n", ret);
return 0;
}
2.strtok
char * strtok ( char * str, const char * sep );
功能:用于分割字符串
实现方式:
- sep参数是个字符串,定义了用作分隔符的字符集合
- 第一个参数是一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
- strtok函数找到str中的下一个标记,并将其用’0’结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改)
- 若strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
- 若strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
- 如果字符串中不存在更多的标记,即全部分割完毕,则返回 NULL 指针。
使用示例:
int main()
{
char arr[] = "Qinshangyan@qq.com";
char sep[] = "@.";
//strtok函数会修改字符串
//所以用临时拷贝分割
char copy[30] = {0};
strcpy(copy, arr);
char* ret = NULL;
//除了第一次切割外,我们想要再次切割,就要在第一个参数传入NULL
//即告诉函数我们要继续切割
//如果全部分割完毕,函数会返回一个空指针,否则就返回一个指向这个标记的指针
for (ret = strtok(copy, sep); ret != NULL; ret = strtok(NULL, sep))
{
printf("%s\n", ret);
}
return 0;
}
(四)错误信息报告
strerror
功能:返回错误码,所对应的错误信息。
错误码:库函数在执行时发生错误,会将一个错误码存放到errno这个变量中(int 类型,声明在头文件errno.h中,errno是C语言提供的一个全局变量)
使用示例:
部分错误码对应的错误信息:
(五)字符分类函数(选看)
1.判断字符函数
函数 | 如果其参数符合下列条件就返回真 |
---|---|
isdigit | 十进制数字 0~9 |
isxdigit | 十六进制数字,包括所有十进制数字,小写字母a~f,大写字母A ~F |
islower | 小写字母a~z |
isupper | 大写字母A~Z |
isalpha | 字母a~z或A ~Z |
isalnum | 字母或者数字,a~z,A ~Z,0 ~9 |
ispunct | 标点符号,任何不属于数字或者字母的图形字符(可打印) |
isgraph | 任何图形字符 |
isprint | 任何可打印字符,包括图形字符和空白字符 |
iscntr | 任何控制字符 |
isspace | 空白字符:空格‘ ’,换页‘\f’,换行’\n’,回车‘\r’,制表符’\t’或者垂直制表符’\v’ |
2.部分字符转换函数
int tolower ( int c );转换成小写
int toupper ( int c );转换成大写
使用示例: