文章目录
一、字符分类函数
C语⾔中有⼀系列的函数是专⻔做字符分类的,也就是⼀个字符是属于什么类型的字符的,这些函数的使⽤都需要包含⼀个头⽂件是 ctype.h
如下图:
这些函数的使用方式十分类似,现在拿一个函数举例:
int islower ( int c );
islower 是能够判断参数部分的 c 是否是小写字母的,通过返回值来说明是否是小写字母,如果是小写字母就返回非0的整数,如果不是小写字母,则返回0
练习:写⼀个代码,将字符串中的小写字母转大写,其他字符不变,最后将其打印出来
分析:首先我们可以创建一个字符数组存放字符串,随后对数组遍历,每一次都使用函数islower函数判断一下该字符是否是小写字母,如果是小写字母,那就给它-32,让它变成对应的大写字母,最后我们以%s的形式将数组打印出来即可(记得包含头文件ctype.h)
代码如下:
#include <stdio.h>
#include <ctype.h>
int main()
{
char arr[] = "Hello World!";
int sz = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < sz-1; i++)
{
if (islower(arr[i]))
{
arr[i] -= 32;
}
}
printf("%s\n", arr);
return 0;
}
运行结果:
二、字符转换函数
C语言提供了两个字符转换函数,要使用它们同样要包含头文件ctype.h:
int tolower ( int c ); //将参数传进去的⼤写字⺟转⼩写
int toupper ( int c ); //将参数传进去的⼩写字⺟转⼤写
于是我们之前的那个将小写字母转换为大写字母的练习就可以这样写:
#include <stdio.h>
#include <ctype.h>
int main()
{
char arr[] = "Hello World!";
int sz = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < sz-1; i++)
{
if (islower(arr[i]))
{
toupper(arr[i]);
}
}
printf("%s\n", arr);
return 0;
}
三、strlen的使用和模拟实现
首先我们来看看strlen的原型:
size_t strlen ( const char * str );
strlen的特点:
- 字符串以 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前⾯出现的字符个数(不包含 ‘\0’ )
- 参数指向的字符串必须要以 ‘\0’ 结束。
- 注意函数的返回值为 size_t,是⽆符号的( 易错 )
- strlen的使⽤需要包含头⽂件string.h
当我们知道strlen的原理后我们就试着来模拟实现一下我们自己的strlen:
- 函数命名:my_strlen
- 函数参数:直接照抄原函数strlen的参数,如下:
size_t my_strlen(const char* p)
- 函数实现:
(1)由于我们传递的是指针,所以为了保险,我们可以在函数开头使用assert对p进行断言,注意包含头文件assert.h
(2)然后我们可以创建一个start指针变量,用于存放初始的p的地址
(3)随后使用while循环,如果对p解引用不是\0,那么就进入循环对p进行++操作,如果是\0,那么循环自动结束
(4)最后返回此时p和start的差值即可 - 函数代码:
#include <assert.h>
size_t my_strlen(const char* p)
{
assert(p);
const char* start = p;
while (*p)
{
p++;
}
return p - start;
}
- 函数测试:如图:
四、strcpy的使用和模拟实现
函数strcpy的作用是拷贝字符串,比如我们要把一个数组中的字符串拷贝到另一个数组中,我们就会使用strcpy函数,使用它需要包含头文件string.h,接下来我们来看看函数strcpy的原型:
char* strcpy(char * destination, const char * source );
原型解析:strcpy的第一个参数是我们拷贝字符串的目的地的首地址,也就是接收拷贝的数组的首元素地址,第二个参数是我们拷贝字符串的源字符串的首地址,它的返回值就是接收拷贝的目标空间的初始地址
了解了它的原型,我们现在来看看它的特点:
- 源字符串必须以 ‘\0’ 结束
- 会将源字符串中的 ‘\0’ 拷⻉到⽬标空间
- ⽬标空间必须⾜够⼤,以确保能存放源字符串
- ⽬标空间必须可修改
现在我们来使用一下它,把数组arr2的字符串拷贝到arr1当中,如图:
可以看到strcpy帮我们把数组arr2的字符串拷贝给了arr1
学会使用,以及了解了它的使用方法之后,我们来试着模拟实现一下strcpy:
- 函数命名:my_strcpy
- 函数参数:可以直接照抄strcpy原型的参数,但是为了方便,我们把名字改简单一点,如下:
char* my_strcpy(char* str1, const char* str2)
- 函数实现:
(1)由于接收的是两个指针参数,所以我们最好首先使用assert进行断言
(2)由于要返回目标空间的起始地址,所以我们还是创建一个start变量来存放刚开始的str1,最后用于返回
(3)strcpy函数的原理就是把源字符串的字符一个一个拷贝给目标字符串,所以我们可以使用while循环,对str2解引用,然后赋值给*str1,把这个赋值表达式作为循环判断条件,然后每执行一次就对str1和str2++一次,如果中途遇到赋值到\0,那么赋值表达式的结果为\0,自动停止循环如下:
while (*str1 = *str2)
{
str1++;
str2++;
}
(4)我们可以优化一下上面的代码,既然str1和str2都要++的,我们可以直接写到循环条件里去,如下:
while (*str1++ = *str2++)
{
;
}
这样比较简洁
(5)最后实现拷贝后,我们就可以返回start了
- 函数代码:
#include <assert.h>
char* my_strcpy(char* str1, const char* str2)
{
assert(str1 && str2);
char* start = str1;
while (*str1++ = *str2++)
{
;
}
return start;
}
- 函数测试:如图:
五、strcat的使用和模拟实现
函数strcat的作用是追加字符串,把一个字符串追加到指定字符串的末尾,使用它要包含头文件string.h,接下来我们来看看strcat的原型
char * strcat ( char * destination, const char * source );
strcat函数原型:它的参数和strcpy类似,第一个参数是被追加的目的地的首地址,第二个参数是要追加的源数据的首地址,返回的也是被追加的目的地的首地址
了解了它的原型后,我们来看看它的特点:
- 源字符串必须以 ‘\0’ 结束
- ⽬标字符串中也得有 \0 ,否则没办法知道追加从哪⾥开始
- ⽬标空间必须有⾜够的⼤,能容纳下源字符串的内容
- ⽬标空间必须可修改
了解strcat的特点后,我们来试着使用它,把字符串数组arr2的字符串追加到字符串数组arr1后:
随后我们来试试模拟实现一下strcat:
- 函数命名:my_strcat
- 函数参数:可以直接照抄strcat原型的参数,但是为了方便,我们把名字改简单一点,如下:
char* my_strcat(char* str1, const char* str2)
- 函数实现:
(1)还是老步骤,接收指针首先使用assert对它们断言一下
(2)strcat函数就是把源字符串放在目标字符串后面,我们就要思考一下是放在目标字符串的哪个字符的后面,是不是\0后面呢?很明显不是,因为如果是\0后面,在打印时会提前碰到目标字符串的\0,结束打印,而不会打印后面追加的内容
(3)所以可以得出,在追加时,strcat会从目标字符串的\0处开始追加,会覆盖目标字符串的\0,所以第一步我们就要先把str1移动到\0那个位置,还是可以使用我们的while循环,如下:
while (*str1)
{
str1++;
}
(4)注意这里不能把循环条件写成str1++,因为如果str是\0了,循环是照常结束,但是str还要++一次,str就指向\0后面了,根据我们前面的分析就是错误的,所以这里只能把str自增的语句写在循环体内,当然,如果是拷贝字符串则不用担心这一点,可以放心把自增写在循环判断条件中
(5)然后我们继续分析,经过上面的循环,我们的str1指向的就是\0了,接着我们就把str2字符串完整的拷贝过来就可以了,这个拷贝的过程可以参考strcpy,可以把自增条件写在循环判断条件中,如下:
while (*str1++ = *str2++)
{
;
}
- 函数代码:
#include <assert.h>
char* my_strcat(char* str1, const char* str2)
{
assert(str1 && str2);
char* start = str1;
while (*str1)
{
str1++;
}
while (*str1++ = *str2++)
{
;
}
return start;
}
- 函数测试:如下图:
最后我们思考一下,一个字符串能不能使用strcat自己给自己追加?如图:
很明显失败了,这是为什么呢?原因在下一篇字符函数和字符串函数(2)中我们会讲到,要实现这个功能需要另一个函数strncat,到时候也会详细介绍以及实现这个函数,期待一下吧!
六、strcmp的使用和模拟实现
strcmp的作用就是帮我们比较两个字符串的大小,那么比较的依据是什么呢?是字符的acsll码值,同样的,使用该函数要包含头文件string.h,我们来看看它的原型:
int strcmp ( const char * str1, const char * str2 );
原型解析:strcmp的两个参数分别是两个字符串的首字符地址,如果前一个字符串大于后一个字符串,返回一个大于0的数,如果相等就返回0,如果小于就返回一个小于0的数
接着我们来看看strcmp的特点:
- 第⼀个字符串⼤于第⼆个字符串,则返回⼤于0的数字
- 第⼀个字符串等于第⼆个字符串,则返回0
- 第⼀个字符串⼩于第⼆个字符串,则返回⼩于0的数字
- 那么如何判断两个字符串? 比较两个字符串中对应位置上字符ASCII码值的大小
了解了这些之后,我们来尝试使用一下strcmp函数来比较两个字符串,技巧就是用一个变量接收strcmp的返回值,然后根据返回值来确定两个字符串的大小关系,如下:
现在我们来模拟实现一下strcmp:
- 函数命名:my_strcmp
- 函数参数:可以直接照抄strcmp原型的参数,如下:
int my_strcmp ( const char* str1, const char* str2 );
- 函数实现:
(1)首先还是对两个指针变量断言一下
(2)我们可以用一个while循环,判断一下 *str1 和 *str2是否相等,如果相等就进入循环,然后对str1和str2进行++操作
(3)要注意的一点是,有可能它们两个字符串完全相等,我们可以判断一下 *str1是否是\0,由于它们解引用后相等才会进入循环,所以此时 *str2也是\0,此时就说明两个字符串完全相等,直接返回0
(4)如果出了循环,说明它们当前指向的字符不相同,所以此时我们直接返回它们的差值即可,如果前一个字符更大,差值就自然大于0,符合函数的情况,后一个字符大也同理,这样我们就实现了我们的strcmp - 代码:
#include <assert.h>
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;
}
- 函数测试:如图:
这次的字符函数和字符串函数(1)就介绍到这里,更多的相关函数请期待下文!
感谢阅读!