字符串基础
字符串就是一串零个或多个字符, 并且以一个位模式为0的 NUL('\0') 字节结尾.
头文件 string.h 包含了使用字符串函数所需要的原型和声明.
字符串长度
字符串长度就是它所包含的字符个数.
库函数 strlen 的原型如下:
size_t strlen(char const *string);
size_t 类型在头文件 stddef.h 中定义, 它是一个无符号的整数类型.
if (strlen(x) >= strlen(y))... if (strlen(x) - strlen(y) >= 0)...
上面两个表达式看上去相等, 但事实不是, 第一个是正常可以工作的, 但是第二个 将永远是真. strlen 的结果是无符号, 所以操作符>=左边表达式也将是无符号数, 而无符号数绝不可能是负的
标准库函数有时是用汇编语言实现的, 目的就是为了充分利用某些机器所提供的特殊 字符串操纵指令追求最大限度的速度.
寻找一种更好的算法比改良一种差劲的算法更有效率, 复用已经存在的软件比重新 开发一个效率更高
不受限制的字符串函数
最常用的字符函数都是 "不受限制" 的, 它们只通过寻找字符参数结尾的 NUL 字节 判断它的长度.
这些函数一般都指定一块内存用于存放结果字符串. 在使用这些函数时, 程序员必须 保证结果字符串不会溢出内存块.
复制字符串
strcpy 原型如下:
char *strcpy(char *dst, char const *src);
这个函数把参数 src 字符串复制到 dst 参数. 如果参数 src 和 dst 在内存中出现 重叠, 其结果是未定义. 由于 dst 参数将进行修改, 所以它必须是个字符数组或者 是一个指向动态分配内存的数组指针, 不能使用字符串常量.
dst 的空间必须足以容纳 src.
连接字符串
strcat 函数可以把一个字符串添加到另一个字符串后面:
char *strcat(char *dst, char const *src);
它找到字符串的末尾, 并把 src 字符串的一份拷贝添加到这个位置.
dst 必须有足够的空间来连接 src
函数返回值
strcpy 和 strcat 都返回它们第一个参数的一份拷贝, 就是一个指向目标数组的 指针.
字符串比较
库函数 strcmp 用于比较两个字符串, 原型如下:
int strcmp(char const *s1, char const *s2);
s1 小于 s2, 返回一个小于零的值, 如果 s1 大于 s2, 返回一个大于零的值. 如果相等, 函数返回零
长度受限的字符函数
标准库还包含一些函数接受一个显示的长度参数, 用于限定进行复制或者比较的字符 数.
这些函数的原型如下所示:
char *strncpy(char *dst, char const *src, size_t len); char *strncat(char *dst, char const *src, size_t len); int strncmp(char const *s1, char const *s2, size_t len);
strncat 总是在结果字符串后面添加一个 NUL 字节, 它最多想目标数组复制 len 个字符(再加一个结尾的 NUL 字节), 不管目标参数源字符串之后知否留下的空间 够不够.
strncmp 也用于比较两个字符串, 但它最多比较 len 的字节.
字符串查找基础
查找一个字符
strchr 和 strrchr 函数用于在字符串中查找一个字符:
char *strchr(char const *str, int ch); char *strrchr(char const *str, int ch);
strchr 在字符串 str 中查找 ch 第一次出现的位置, 找到后函数返回一个指向该 位置的指针. 如果该字符不存在返回 NULL 子真.
strrchr 和 strchr 基本一直, 只是它所返回的是一个指向字符串中该字符最后一次 出现的位置.
查找任何几个字符
strpbrk 用于查找任何一组字符第一次出现的位置:
char *strpbrk(char const *str, char const *group);
char string[20] = "Hello there, honey."; char *ans; ans = strpbrk(string, "aeiou");
ans 所指向的位置是 string + 1, 因为这个位置是第二个参数中字符第一次出现的 位置.
查找一个子串
strstr 函数用于查找一个子串:
char *strstr(char const *s1, char const *s2);
标准库并不存在 strrstr 或 strrpbrk 函数.
高级字符串查找
查找一个字符串前缀
strspn 和 strcspn 函数用于在字符串的起始位置对字符计数:
size_t strspn(char const *str, char const *group); size_t strcspn(char const *str, char const *group);
strcspn 函数和 strspn 函数正好相反, 他对 str 字符串起始部分中不与 group 中 任何字符串匹配的字符进行计数. c 来源自对一组字符求补的这个概念, 也就是把这 些字符换成原先不存在的字符.
查找标记
strtok 函数从字符串中隔离哥哥单独的称为标记(token)的部分, 并丢弃隔离符.
char *strtok(char *str, char const *sep);
错误信息
strerror 函数把变量 errno 其中一个错误代码作为参数并返回一个指向用于描述 错误的字符串指针.
char *strerror(int error_number);
字符操作
标准库包含了两组函数, 用于操作单独的字符, 它们的原型位于头文件 ctype.h
第一组函数对字符分类, 第二组函数用于转换字符.
字符分类
每个分类函数接受一个包含字符值的整型参数.
函数 | 如果它的参数符号下列条件就返回值 |
---|---|
iscntrl | 任何控制字符 |
isspace | 空白字符 |
isdigit | 十进制数字 0~9 |
isxdigit | 十六进制数组 |
islower | 小写字母 |
isupper | 大写字母 |
isalpha | 字母 a~z/A~Z |
ispunct | 标点符号 |
isgraph | 图形符号 |
isprint | 任何可打印字符 |
字符转换
转换函数把用于字母大小写转换
int tolower(int ch); int toupper(int ch);
内存操作
void *memcpy(void *dst, void const *src, size_t length); void *memmove(void *dst, void const *src, size_t length); void *memcmp(void const *a, void const *b, size_t length); void *memset(void *a, int ch, size_t length);
每个原型都包含了一个显示的参数说明需要处理的字节数. 和 strn 带头的函数 不同, 他们遇到 NUL 字节时并不会停止操作
memcpy 从 str 的起始位置复制 length 字节到到 dst 的内存的起始位置. 你可以 用这种方法复制任何类型的值, 第3个参数指定复制值的长度(单位字节). 如果 str 和dst 以任何形式出现了重叠, 它的结果是未定义.
memmove 函数行为和 memcpy 差不多, 只是它的源和目标操作数和可以重叠. memmove 通常无法使用某些机器所提供的特殊字节-字符串处理指令来实现, 所以 它可能比 memcpy 慢一些. 但是, 如果源和目标参数真的可能存在重叠, 就应该 使用memmove.
memcpm 对两段内存内容进行比较. 这段内存分别起始与 a 和 b, 共比较 length 个 字节. 这些值按照无符号字符逐字节比较, 函数返回类型和 strcmp 函数一样.
正是这些值根据一串无符号字节进行比较的, 所以如果 memcmp 函数用于比较不是单字节的数据如整数或浮点数时可能给出不可预料的结果.
memchr 从 a 的起始位置开始查找字符 ch 第一次出现的位置, 并返回一个指向该 位置的指针, 它共查找 length 个字节. 如位找到, 返回 NULL 指针.
memset 函数把 a 开始的length 个字节都设置为字符值 ch, 如:
memset(buffer, 0, SIZE);
把 buffer 的前SIZE个字节都初始化为0.