文/Edward
在C语言的实际使用中,很多时候会去使用指针传递一些字符串,而C语言中也有很多关于字符串处理的库函数给大家来使用,只要在使用的时候包含头文件“string.h”就可以使用它们了。接下来的内容中,我们将使用之前学习过的内容自己写一些代码来实现几个这些库函数可以提供给我们的功能,实现完成之后,再介绍相应的库函数。
字符串长度的测量
一说到长度的测量,很多人脑中第一时间就会联想到sizeof关键词,我们可以先使用这个关键词写一个字符串测量的程序来试试看此方法是否可行。我们在一个程序里面定义三种类型的字符串,第一种类型定义的字符串是使用数组存放的字符串,第二种类型是直接使用指针存放的字符串常量,第三种类型是使用指向字符串的指针,定义好之后分别使用sizeof测量它们的长度。如图1所示。
图1 sizeof测量字符串长度
在图1中,我们可以发现,除了使用sizeof测量字符数组存放的字符串时,输出的结果是我们预期的结果之外,其余两种方法全部都是错误的,那么这个8到底是哪来的呢?
这个代码中使用sizeof直接去测量一个指针变量,其实它测量的东西和char这种类型是没有关系的,它应该测量的是“char*”这种类型,这种字符型指针类型里面存放的应该是这个变量的地址。而我们这个64位的计算机中,都是使用一个64位长度的变量来存放这个地址的,所以最终会输出结果为8,这个8指的是8字节。顺便我们可以测一下int *这种类型的长度,如图2所示。
图2 测量指针的长度
以上的结果对于我们来说显然是不满足要求的,我们需要设计一种字符串长度测量的方法,可以同时测试不同情况下存储的字符串,并且还需要将字符串的结束字符“\0”不计入在内。
正如上面所说的,不管存放在那种存储结构里面的字符串,只要它是一个字符串,都必须满足以特殊字符“\0”结尾的规律,因此只需要牢牢抓住这个规律,即可实现字符串的长度测量。对于这样的一个函数,对外的接口参数定义成一个字符型指针,返回值即返回传入字符串的长度。而函数体的实现,定义一个while循环,判断当前指针指向的字符是否为“\0”,如果当前指向的字符不为“\0”,则将字符串的长度加1,如果为“\0”,则退出循环。代码的实现如图3所示。
图3 测量字符串长度的实现代码
在C语言的库函数中,也提供了字符串长度测量的库函数,这个库函数就是“strlen”,strlen的原型为“size_t strlen(const char *str)”,其中size_t是返回的字符串的长度,其实这个值就是一个int,只不过重新对其用typedef定义了。而*str这个形式参数即为我们需要输入的字符串。将上面的程序改写成strlen如图4所示。
图4 库函数strlen测量字符串长度
从代码定义中我们也可以找到,strlen的返回类型size_t在C语言中也有相关的定义,如图5所示。
图5 size_t类型定义
字符串字符的查找
字符串字符的查找也是C语言中常用的操作,比如,当我们要判断一个字符串里面是否包含某个字符或者字符串字段的时候,我们会频繁使用这种操作。现在我们先自己写一段代码来解析某个字符串是否含有某个字母。具体实现代码如图6所示。
图6 查找字符串中是否包含某个字符
图6种,我们写了一个函数stringChar来查找字符串中是否包含某个字符,如果包含则返回这个字母所在字符串的位置,如果不包含则返回0。而在C语言的库函数中,也有这个功能的库函数,strchr,其原型为“char *strchr(const char *str, int c)”。我们可以用个库函数来改写以下代码,如图7所示。
图7 strchr库函数实现代码
关于C语言字符串处理的库函数还有非常多的功能函数,如图8所示,这些库函数的使用,我们在以后的设计中会经常用到,具体用法用到的时候再详细说。
图8
字符串处理库函数
序号 | 函数体 | 描述 |
1 | void *memchr(const void *str, int c, size_t n) | 在参数 str 所指向的字符串的前 n 个字节中搜索第一次出现字符 c(一个无符号字符)的位置。 |
2 | int memcmp(const void *str1, const void *str2, size_t n) | 把 str1 和 str2 的前 n 个字节进行比较。 |
3 | void *memcpy(void *dest, const void *src, size_t n) | 从 src 复制 n 个字符到 dest。 |
4 | void *memmove(void *dest, const void *src, size_t n) | 另一个用于从 src 复制 n 个字符到 dest 的函数。 |
5 | void *memset(void *str, int c, size_t n) | 复制字符 c(一个无符号字符)到参数 str 所指向的字符串的前 n 个字符。 |
6 | char *strcat(char *dest, const char *src) | 把 src 所指向的字符串追加到 dest 所指向的字符串的结尾。 |
7 | char *strncat(char *dest, const char *src, size_t n) | 把 src 所指向的字符串追加到 dest 所指向的字符串的结尾,直到 n 字符长度为止。 |
8 | char *strchr(const char *str, int c) | 在参数 str 所指向的字符串中搜索第一次出现字符 c(一个无符号字符)的位置。 |
9 | int strcmp(const char *str1, const char *str2) | 把 str1 所指向的字符串和 str2 所指向的字符串进行比较。 |
10 | int strncmp(const char *str1, const char *str2, size_t n) | 把 str1 和 str2 进行比较,最多比较前 n 个字节。 |
11 | int strcoll(const char *str1, const char *str2) | 把 str1 和 str2 进行比较,结果取决于 LC_COLLATE 的位置设置。 |
12 | char *strcpy(char *dest, const char *src) | 把 src 所指向的字符串复制到 dest。 |
13 | char *strncpy(char *dest, const char *src, size_t n) | 把 src 所指向的字符串复制到 dest,最多复制 n 个字符。 |
14 | size_t strcspn(const char *str1, const char *str2) | 检索字符串 str1 开头连续有几个字符都不含字符串 str2 中的字符。 |
15 | char *strerror(int errnum) | 从内部数组中搜索错误号 errnum,并返回一个指向错误消息字符串的指针。 |
16 | size_t strlen(const char *str) | 计算字符串 str 的长度,直到空结束字符,但不包括空结束字符。 |
17 | char *strpbrk(const char *str1, const char *str2) | 检索字符串 str1 中第一个匹配字符串 str2 中字符的字符,不包含空结束字符。也就是说,依次检验字符串 str1 中的字符,当被检验字符在字符串 str2 中也包含时,则停止检验,并返回该字符位置。 |
18 | char *strrchr(const char *str, int c) | 在参数 str 所指向的字符串中搜索最后一次出现字符 c(一个无符号字符)的位置。 |
19 | size_t strspn(const char *str1, const char *str2) | 检索字符串 str1 中第一个不在字符串 str2 中出现的字符下标。 |
20 | char *strstr(const char *haystack, const char *needle) | 在字符串 haystack 中查找第一次出现字符串 needle(不包含空结束字符)的位置。 |
21 | char *strtok(char *str, const char *delim) | 分解字符串 str 为一组字符串,delim 为分隔符。 |
22 | size_t strxfrm(char *dest, const char *src, size_t n) | 根据程序当前的区域选项中的 LC_COLLATE 来转换字符串 src 的前 n 个字符,并把它们放置在字符串 dest 中。 |