1、字符串基础
字符串是一种重要的数据类型,但是C语言并没有显式的字符串数据类型,因为字符串以字符串常量的形式出现或者存储于字符数组中。
字符串就是一串零个或多个字符,并且以一个位模式为全0的NUL字节结尾。因此,字符串所包含的字符内部不能出现NUL字节。NUL字节是字符串的终止符,但他本身并不是字符串的一部分,所以字符串的长度并不包括NUL字节。
2、字符串长度
库函数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,就可以消除这个问题
3、字符串复制
库函数strcpy的原型如下:
char *strcpy(char * dst, char const * src)
这个函数把参数src字符串复制到dst参数。如果src和dst在内存中存在重叠,其结果是未定义的。
由于dst参数将进行修改,所以它不能使用字符串常量。
目标参数的以前内容将被覆盖并丢失。即使新的字符串比dst原先的内存更短,由于新字符串是以NUL字节结尾,所以老字符串最后剩余的几个字符也被有效地删除。
程序猿必须保证目标字符数组的空间足以容纳需要复制的字符串。如果字符串比数组长,多余的字符仍被复制,它们将覆盖原先存储于数组后面的内存空间。strcpy无法结果这个问题,因为它无法判断目标字符数组的长度。
返回值:指向目标字符数据的指针。
4、连接字符串
库函数strcat的原型如下:
char *strcat(char *dst, char const *src)
函数功能是把一个字符串添加(连接)到另一个字符串的后面。
函数要求dst参数原先已经包含了一个字符串(可以是空字符串)。它找到这个字符串的末尾,并把src字符串的一份拷贝添加到这个位置,如果dst和src的位置发生重叠,其结果是未定义的。
和前面一样,程序猿必须保证目标字符数组剩余的空间足以保存整个源字符串。同时,你必须考虑原先存在的字符串
返回值:指向目标字符数据的指针。
5、字符串比较
库函数strcmp的原型如下:
int strcmp(char const *s1, char const *s2)
比较两个字符串涉及对两个字符串对应的字符逐个进行比较,直到发现不匹配为止。那个最先不匹配的字符中较“小”(也就是说,在字符集中的序数较小)的那个字符所在的字符串被认为“小于”另外一个字符串。如果其中一个字符串是另外一个字符串前面的一部分,那么它也被认为“小于”另外一个字符串,
因为它的NUL结尾字节出现的更早。这种比较被称为“词典比较”
返回值:如果s1小于s2,函数返回一个小于零(非零即为真)的值。如果s1大于s2,函数返回一个大于零(非零即为真)的值,如果两个字符串相等,函数就返回零(零就是假)
例如函数:
if (strcmp(a, b))
这样比较是得不出真确结果的,更好的方法是把这个返回值与零进行比较。
6、长度受限的字符串函数
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个字节
7、字符串查找基础
a、查找一个字符串
char *strchr(char const *str, int ch)
char *strrchr(char const *str, int ch)
注意它们的第2个参数是一个整型值。但是,它包含了一个字符值。strchr在字符串str中查找字符ch第一个出现的位置,找到后函数返回一个指向该位置的指针。如果该字符并不存在于字符串中函数就返回一个NULL指针。strrchr功能基本一致,只是它所返回的是一个指向字符串中该字符最后一次出现的位置(最右边那个),区分大小写
b、查找任何几个字符
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,区分大小写
3、查找一个子串
char *strstr(char const *s1, char const *s2)
这个函数在s1中查找整个s2第一次出现的位置,并返回一个执行该位置的指针。如果s2并没有完整的出现在s1的任何地方,函数返回一个NULL指针。如果第二个参数是一个空字符串,函数就返回s1.
注意标准库中并没有strstr或strpbrk函数
8、警告的总结:
1、应该使用有符号数的表达式中使用strlen函数
2、在表达式中混用有符号数和无符号数
3、使用strcpy函数把一个长字符串复制到一个较短的数组中,导致溢出
4、使用strcat函数把一个字符串添加到一个数组中,导致数组溢出
5、把strcmp函数的返回值当做bool值进行测试
6、把strcmp函数的返回值与1和-1进行比较
7、使用并非以NUL字节结尾的字符序列
8、使用strncpy函数产生不以NUL字节结尾的字符串
9、把strncpy函数和strxxx函数混用
9、sizeof和strlen的区别:
strlen是C语言的库函数,如上所述,strlen 测量的是字符的实际长度,以'\0' 结束。
sizeof是C语言的运算符,sizeof 测量的是字符的分配大小。其作用是返回一个对象或者类型在内存中所占用的字节数。
注意:sizeof后面如果是类型则必须加括号,如 sizeof(char);而如果是变量名则可以不加括号,如 sizeof a; 但是建议使用时 均加上括号。sizeof不能返回动态地被分配的数组的大小。
sizeof可以用类型做参数,strlen只能用char*做参数,且必须是以''\0''结尾的。
.strlen的结果要在运行的时候才能计算出来,是用来计算字符串的长度,不是类型占内存的大小。而大部分编译程序在编译的时候就把sizeof计算过了是类型或是变量的长度。
在子函数中,ziseof 会把从主函数中传进来的字符数组当作是指针来处理。指针的大小又是由机器来决定,而不是人为的来决定的。
10、示例1
#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
*/