Hi~!这里是奋斗的小羊,很荣幸各位能阅读我的文章,诚请评论指点,关注+收藏,欢迎欢迎~~
💥个人主页:小羊在奋斗
💥所属专栏:C语言
本系列文章为个人学习笔记,在这里撰写成文一为巩固知识,二为同样是初学者的学友展示一些我的学习过程及心得。文笔、排版拙劣,望见谅。
1、字符分类函数
2、字符转换函数
3、strlen 的使用和模拟实现
4、strcpy 的使用和模拟实现
5、strcat 的使用和模拟实现
1、字符分类函数
C语言中有一些专门作字符分类的函数,使用这些函数需要包含头文件 ctype.h 。
isalnum | 检查一个字符是否是字母或数字 (函数) |
isalpha | 检查一个字符是否是字母 (函数) |
islower | 检查一个字符是否是小写字母 (函数) |
isupper | 检查一个字符是否是大写字母 (函数) |
isdigit | 检查字符是否为数字 (函数) |
isxdigit | 检查一个字符是否是十六进制的字符 (函数) |
iscntrl | 检查一个字符是否是控制字符 (函数) |
isgraph | 检查一个字符是否是图形字符 (函数) |
isspace | 检查一个字符是否是空白字符 (函数) |
isblank (C99) | 检查一个字符是否是空格字符 (函数) |
isprint | 检查一个字符是否是可打印字符 (函数) |
ispunct | 检查一个字符是否是标点字符 |
更多详细内容请点击跳转阅读 —> C 标准库头文件 - cppreference.com
这些函数的使用方法、返回值等基本是一致的,这里就以 islower 函数为例,写一个将字符串中非大写的字母转化为大写字母的示例。
2、字符转换函数
C语言中有两个实现大小写转换的函数,tolower(将大写字母转小写) 和 toupper(将小写字母转大写)。
那既然有了这两个函数,上面将字符串中的小写字母转换为大写字母的代码就可以简化一下了。
3、strlen 的使用和模拟实现
3.1 strlen 的返回值
strlen 函数我们已经非常的熟悉,之前也介绍了两种模拟 strlen 函数的方法,这里再关于strlen 的使用做一些补充,同时再介绍另一种 strlen 的模拟实现方法。
以前我们在使用 strlen 函数的时候,可能没有细心地关注过 strlen 的返回值类型,有时候我们使用 int 类型来接收它的返回值好像也没出现什么问题,但其实这是一个很值得我们去注意的一个问题。来看下面的示例:
按道理来说-3小于0应该打印的是“<=”,但结果却并不是。其中的原因就在于 strlen 的返回值类型是 size_t 类型,两个 size_t 类型的值相减还是 size_t 类型,而我们知道整型是以补码的形式存储的,所以 size_t 类型会把-3的补码当做一个很大的正整数,这个数当然是大于0的,所以结果是打印出了 “>”。而如果我们想让它输出我们想要的结果,只需要强制类型转换就行。
3.2 strlen 的模拟实现
之前的文章中我们用了指针遍历数组和指针-指针两种方法来模拟 strlen 函数,这里我们再使用另一种方法来模拟实现——递归。
#include <stdio.h>
#include <assert.h>size_t my_strlen(char* str)
{assert(str != NULL);if (*str != '\0'){return 1 + my_strlen(++str);}else{return 0;}
}int main()
{char str[] = "Are you ok?";size_t len = my_strlen(str);printf("%zd\n", len);return 0;
}
我们之前说过,递归就是一个把大事化小的过程,适合于解决一些简单重复的操作,就像上面重复读取一个字符并判断的过程。这个方法很简单,一眼就能明白其中的原理,我就不过多阐述了。值得一说的是,这个方法并没有创建新变量,这是区别于前两种方法的地方。
4、strcpy 的使用和模拟实现
4.1 strcpy 的用法
strcpy 是一个字符串拷贝函数,它的作用是把第二个参数所指的字符串拷贝给第一个参数所指的字符串数组中,注意不要搞反了。
更多详细介绍请点击查阅 —> strcpy, strcpy_s - cppreference.com
使用 strcpy 也需要包含头文件 <string.h>,是比较简单的,但是有几个需要特别注意的点。
(1)源字符串必须以 ‘\0’ 结束;
就像 strlen 函数一样,strcpy 函数也需要知道它应该在哪里停止拷贝。
(2)会将源字符串中的 ‘\0’ 拷贝到目标空间;
在上面的代码中我们使用 strlen 函数证明了这点。
(3)目标空间必须足够大,以确保能放得下字符串;
以上面的代码为例,如果我们定义的字符数组 str2 太小,程序就会出错。
(4)目标空间必须可修改。
这里举个反例来证明这一点。
将常量字符串 “abc” 存到字符指针变量 ps 中,前面说过常量字符串是不能被修改的,所以程序就出错了。
4.2 strcpy 的模拟实现
就像 strlen 函数一样,我们同样也可以模拟实现一个 strcpy 函数,完成字符串拷贝的功能。
#include <stdio.h>
#include <assert.h>
#include <string.h>void my_strcpy(char* dest, const char* sour)
{assert(dest != NULL);assert(sour != NULL);while (*sour != '\0'){*dest = *sour;sour++;dest++;}*dest = *sour;//\0
}int main()
{char str1[] = "what can I say? man.";char str2[50] = { 0 };my_strcpy(str2, str1);printf("%s\n", str2);printf("%zd\n", strlen(str2));return 0;
}
逻辑也是特别简单的,只不过我们要特别注意字符 ‘\0’ 也需要拷贝过去。
4.3 strcpy 的返回值
关于 strcpy 函数我们可能会忽略了它的返回值,因为我们会觉得这个函数并不需要什么返回值,但其实它是有返回值的,既然有返回值,那它的返回值就有用,所以严格来说我们上面模拟实现的 strcpy 函数返回值应该为 char * 而不是 void 。strcpy 函数返回的是目标字符串的首地址,这使得 strcpy 可以链式操作。
所以上面的代码可以更新为:
#include <stdio.h>
#include <assert.h>
#include <string.h>char* my_strcpy(char* dest, const char* sour)
{assert(dest != NULL);assert(sour != NULL);char* pd = dest;while (*sour != '\0'){*dest = *sour;sour++;dest++;}*dest = *sour;//\0return pd;
}int main()
{char str1[] = "what can I say? man.";char str2[50] = { 0 };char* ps = my_strcpy(str2, str1);printf("%s\n", ps);printf("%s\n", my_strcpy(str2, str1));printf("%zd\n", strlen(str2));return 0;
}
4.4 strcpy 模拟实现的优化
虽然我们已经完成了 strcpy 函数的模拟实现,但上面的代码还可以优化。因为字符‘\0’的特殊,上面的代码中我们是将普通字符和‘\0’字符分开处理的,那是否可以有个办法将这两步合在一起呢?
来体会下面这条代码:
我们用一条代码就实现了拷贝字符串,包括拷贝字符‘\0’。其中的原理也是非常简单,当字符‘\0’拷贝到目的空间后,括号中表达式的值为0,就自动跳出了循环。需要说明的是两个指针变量都是先解引用,然后再自增的。
5、strcat 的使用和模拟实现
5.1 strcat 的用法
strcat 函数的作用是将源字符串拼接到目标字符串的后面,跟 strcpy 函数类似,strcat 是将第二个参数所指的字符串拼接到第一个参数所指的字符串后面。
更多详细的介绍请点击阅读 —> strcat, strcat_s - cppreference.com
同样的,strcat 函数也有几个需要注意的点:
(1)源字符串必须以‘\0’结束;
(2)目标字符串中也得有‘\0’,否则没法知道拼接在哪里;
(3)目标空间必须足够大;
(4)目标空间必须可修改。
5.2 strcat 的返回值
类比 strcpy,strcat 也是有返回值的,并且返回值也是目标字符串的首地址。
5.3 strcat 的模拟实现
我们依然可以自己写一个函数来模拟实现 strcat 的功能,方法很简单,类似于模拟实现 strcpy 的方法,我们只需要想办法将源字符串拼接到目标字符串末尾就行,相信对于现在有点基础的我们来说这并不是什么难事。
#include <stdio.h>
#include <assert.h>char* my_strcat(char* dest, const char* sour)
{assert(dest != NULL);assert(sour != NULL);char* pd = dest;while (*dest++);dest--;//覆盖掉目标字符串中的\0while (*dest++ = *sour++);return pd;
}int main()
{char str1[20] = "hello ";char str2[] = "world";char *ps = my_strcat(str1, str2);printf("%s\n", ps);return 0;
}
上面我们是将一个字符串与另一个字符串拼接在一起,那能不能将一个字符串拼接到自己的末尾呢?
可以看到,用我们自己写的函数不能实现字符串自己拼接到自己后面,这是因为拼接的过程是在目标字符串末尾的 ‘\0’ 处开始拼接的,也就是说目标字符串的第一个字符会覆盖掉它自己末尾的 ‘\0’,那函数的第二个参数指针就永远也找不到 ‘\0’ 以结束拼接,就会陷入死循环。
但是 strcat 函数可以,不过 strcat 函数并不能保证这件事情,也就是说上面能成功是偶然的。
如果觉得我的文章还不错,请点赞、收藏 + 关注支持一下,我会持续更新更好的文章。