字符串基础
字符串是一种重要的数据类型,但是 C 语言并没有显式的字符串数据类型,因为字符串以字符串常量的形式出现或者存储于字符数组中。
字符串就是一串零个或多个字符,并且以一个位模式为全 0 的 NUL 字节结尾。因此,字符串所包含的字符内部不能出现 NUL 字节。NUL 字节是字符串的终止符,但他本身并不是字符串的一部分,所以字符串的长度并不包括 NUL 字节。
字符串长度
库函数 strlen 的原型如下:
size_t strlen(char const *string)
注意 strlen 返回值类型是一个 size_t 类型,这个类型是在头文件 stddef.h 中定义的,它是一个无符号整型类型。
例如:
if (strlen(x) >= strlen(y) ) ----
if (strlen(x) - strlen(y) >= 0)---
上面两条语句看上去是相等的,但实际上并不相等,第一条语句按照你预想的那样工作,但是第二条语句的结果将是永远是真。strlen 的结果是一个无符号数,所以操作符 >= 左边的表达式也将是一个无符号数,而无符号数绝不可能是负的。
如果把 strlen 的返回值强制转换为 int,就可以消除这个问题
测试代码
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
printf("hello world\r\n");
char *ptr1 = "hello world";
char *ptr2 = "tyustli";
if (strlen(ptr2) - strlen(ptr1) > 0)
{
printf(" > 0\r\n");
}
else
{
printf(" < 0\r\n");
}
if (strlen(ptr2) > strlen(ptr1))
{
printf("ptr2 len ptr1\r\n");
}
else
{
printf("ptr2 short ptr1\r\n");
}
printf("%ld %ld\r\n", strlen(ptr1), strlen(ptr2));
return 1;
}
/**
* 编译:gcc -o test test.c
* 运行:./test
* 结果:
* hello world
* tyustli
* > 0
* ptr2 short ptr1
* 11 7
*/
字符串复制
库函数 strcpy 的原型如下:
char *strcpy(char * dst, char const * src)
这个函数把参数 src 字符串复制到 dst 参数。如果 src 和 dst 在内存中存在重叠,其结果是未定义的。
由于 dst 参数将进行修改,所以它不能使用字符串常量。
目标参数的以前内容将被覆盖并丢失。即使新的字符串比 dst 原先的内存更短,由于新字符串是以 NUL 字节结尾,所以老字符串最后剩余的几个字符也被有效地删除。
程序猿必须保证目标字符数组的空间足以容纳需要复制的字符串。如果字符串比数组长,多余的字符仍被复制,它们将覆盖原先存储于数组后面的内存空间。strcpy 无法结果这个问题,因为它无法判断目标字符数组的长度。
返回值:指向目标字符数据的指针。
连接字符串
库函数 strcat 的原型如下:
char *strcat(char *dst, char const *src)
函数功能是把一个字符串添加 (连接) 到另一个字符串的后面。
函数要求 dst 参数原先已经包含了一个字符串 (可以是空字符串)。它找到这个字符串的末尾,并把 src 字符串的一份拷贝添加到这个位置,如果 dst 和 src 的位置发生重叠,其结果是未定义的。
和前面一样,程序猿必须保证目标字符数组剩余的空间足以保存整个源字符串。同时,你必须考虑原先存在的字符串
返回值:指向目标字符数据的指针。
字符串比较
库函数 strcmp 的原型如下:
int strcmp(char const *s1, char const *s2)
比较两个字符串涉及对两个字符串对应的字符逐个进行比较,直到发现不匹配为止。那个最先不匹配的字符中较 小(也就是说,在字符集中的序数较小) 的那个字符所在的字符串被认为 小于 另外一个字符串。如果
其中一个字符串是另外一个字符串前面的一部分,那么它也被认为 小于 另外一个字符串,
因为它的 NUL 结尾字节出现的更早。这种比较被称为 词典比较
返回值:如果 s1 小于 s2,函数返回一个小于零 (非零即为真) 的值。如果 s1 大于 s2,函数返回一个大于零 (非零即为真) 的值,如果两个字符串相等,函数就返回零(零就是假)
例如函数:
if (strcmp(a, b))
这样比较是得不出真确结果的,更好的方法是把这个返回值与零进行比较。
长度受限的字符串函数
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)
strncpy() 把源字符串的字符复制到目标数组。然而,它总是正好向 dst 写入 len 个字符,如果 strlen(src) 的值小于 len,dst 数组就用额外的 NUL 字节填充到 len 长度。如果 strlen(src) 的值大于或等于 len,那么只有 len 个字符被复制到 dst 中。注意,它的结果将不会以 NUL 字节结尾。
strncat(), 他从 src 中最多复制 len 个字符到目标数组的后面。但是 strncat 总是在结果字符串后面添加一个 NUL 字节,
strncmp(),比较两个字符串,但它最多比较 len 个字节
字符串查找基础
查找一个字符串
char *strchr(char const *str, int ch)
char *strrchr(char const *str, int ch)
注意它们的第 2 个参数是一个整型值。但是,它包含了一个字符值。strchr 在字符串 str 中查找字符 ch 第一个出现的位置,找到后函数返回一个指向该位置的指针。如果该字符并不存在于字符串中函数就返回一个 NULL 指针。strrchr 功能基本一致,只是它所返回的是一个指向字符串中该字符最后一次出现的位置 (最右边那个),区分大小写
查找任何几个字符
char *strpbrk(char const *str, char const *group)
查找任何一组字符第一次在字符串中出现的位置
这个函数返回一个指向 str 中第一个匹配 group 中任何一个字符的字符位置。如果未找到匹配,函数返回一个 NULL 指针
例如:
char string[20] = "Hello there, honey.";
char *ans;
ans = strpbrk(string, "aeiou");
ans 所指向的位置时 string+1,区分大小写
查找一个子串
char *strstr(char const *s1, char const *s2)
这个函数在 s1 中查找整个 s2 第一次出现的位置,并返回一个执行该位置的指针。如果 s2 并没有完整的出现在 s1 的任何地方,函数返回一个 NULL 指针。如果第二个参数是一个空字符串,函数就返回 s1.
注意标准库中并没有 strrstr 或 strrpbrk 函数
警告的总结:
- 应该使用有符号数的表达式中使用 strlen 函数
- 在表达式中混用有符号数和无符号数
- 使用 strcpy 函数把一个长字符串复制到一个较短的数组中,导致溢出
- 使用 strcat 函数把一个字符串添加到一个数组中,导致数组溢出
- 把 strcmp 函数的返回值当做 bool 值进行测试
- 把 strcmp 函数的返回值与 1 和 - 1 进行比较
- 使用并非以 NUL 字节结尾的字符序列
- 使用 strncpy 函数产生不以 NUL 字节结尾的字符串
- 把 strncpy 函数和 strxxx 函数混用
## sizeof 和 strlen 的区别:
strlen 是 C 语言的库函数,如上所述, strlen 测量的是字符的实际长度,以 \0 结束。
sizeof 是 C 语言的运算符,sizeof 测量的是字符的分配大小。其作用是返回一个对象或者类型在内存中所占用的字节数。
注意:sizeof 后面如果是类型则必须加括号,如 sizeof(char);而如果是变量名则可以不加括号,如 sizeof a; 但是建议使用时 均加上括号。sizeof 不能返回动态地被分配的数组的大小。
sizeof 可以用类型做参数,strlen 只能用 char * 做参数,且必须是以\0结尾的。
strlen 的结果要在运行的时候才能计算出来,是用来计算字符串的长度,不是类型占内存的大小。而大部分编译程序在编译的时候就把 sizeof 计算过了是类型或是变量的长度。
在子函数中,sizeof 会把从主函数中传进来的字符数组当作是指针来处理。指针的大小又是由机器来决定,而不是人为的来决定的。
1572

被折叠的 条评论
为什么被折叠?



