提示:本文是对C语言基础知识:字符串、字符和字节部分的回顾总结。
C语言并没有显式的字符串数据类型,因为字符串以 字符串常量的形式出现 或者 存储于字符数组中。
字符串 :就是一串零个或多个字符,并且以一个 位模式为全0的 NUL 字节结尾。
NUL字节 是字符串的终止符,但它本身并不是字符串的一部分,所以字符串的长度并不包括 NUL 字节。
头文件 string.h 包含了使用字符串函数所需的原型和声明。
字符串的长度就是它所包含的字符个数。
库函数 strlen 的原型如下:
size_t strlen( char const *string );
strlen返回一个类型为 size_t 的值,这个类型是在头文件 stddef.h 中定义的,它是一个 无符号整数类型 。
/*
** 计算字符串参数的长度
*/
#include
size_t strlen( char const *string )
{
unsigned int length;
for( length = 0; *string++ != '\0'; ) //*string++,是字符串指针string++,然后再取引用
length += 1;
return length;
}
最常用的字符串函数都是“不受限制”的,就是说它们只是通过寻找字符串参数结尾的 NUL 字节来判断它的长度。
复制字符串的函数是 strcpy,原型如下:
char *strcpy( char *dst, char const *src );
/*此函数把参数 src字符串复制到 dst 参数。*/
由于 dst 参数将进行修改,所以它必须是个字符数组或者是一个指向动态内存的数组指针,不能使用字符串常量。
目标参数的以前内容将被覆盖并丢失。即使新的字符串比 dst 原先的内存更短,由于新的字符串是以 NUL字节结尾,,所以老字符串最后剩余的几个字符也将会被有效删除。
例如:
cahr message[] = "Original message";
...
if ( ... )
strcpy( message, "Different" );
程序员必须保证目标字符数组的空间足以容纳需要复制的字符串。
将一个字符串添加(连接)到另一个字符串的后面的函数是 strcat ,原型如下:
char *strcat( char *dst, char const *src );
strcat 函数要求 dst 参数原先已经包含了一个字符串(可以是空字符串)。
程序员必须保证目标字符数组剩余的空间足以保存整个源字符串。
strcpy 和 strcat 都返回它们第 1 个参数的一份拷贝,就是一个 指向目标字符数组的指针
比较两个字符串涉及对两个字符串对应的字符逐个进行比较,直到发现不匹配为止。
库函数 strcmp 用于比较两个字符串,它的原型如下:
int strcmp( char const *s1, char const *s2 );
/*
** 如果s1小于s2,strcmp函数返回一个小于零的值;
** 如果s1大于s2,strcmp函数返回一个大于零的值;
** 如果两个字符串相等,函数就返回零。
*/
由于strcmp并不修改任何的一个参数,所以不存在溢出字符数组的危险。
长度受限的字符串函数提供了一种方便的机制,可以防止难以预料的长字符串从它们的目标数组溢出。
这些函数通过接受一个显式的长度参数,用于限定进行复制或比较的字符数。
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 );
1、strncpy 把源字符串的字符复制到目标数组,它总是正好向 dst 写入 len 个字符:
如果strlen( src )的值小于len,dst 数组就是就用额外的 NUL 字节填充到len长度;
如果strlen( src )的值大于或等于len,那么只有len个字符被复制到 dst 中,注意:它的结果将不会以 NULL字节结尾。
char buffer[BSIZE];
...
strncpy( buffer, name, BSIZE );
buffer[BSIZE - 1] = '\0'; //此语句可以保证buffer中的字符串是以NUL结尾的。
2、strncat 总是在结果字符串后面添加一个 NUL字节,而且它不会像strncpy那样对目标数组用NUL字节进行填充。
3、strncpy 用于比较两个字符串,但它最多比较 len 个字节。
在一个字符串中查找一个特定字符最容易的方法是使用 strchr 和 strrchr 函数,原型如下:
char *strchr( char const *str, int ch );
char *strrchr( char const *str, int ch );
注意:第2个参数是一个整型值,但是它包含了一个字符值。
strchr 在字符串 str 中查找字符 ch 第 1 次出现 的位置,找到后函数返回一个指向该位置的指针。
如果该字符并不在于字符串中,函数就返回一个 NULL 指针。
strrchr 的功能和 strchr 基本一致,只是它所返回的是一个指向字符串中该字符 最后一次出现 的位置。
char string[20] = "Hello there, honey.";
char *ans
ans = strchr( string, 'h' );
/*ans所指向的位置是string+7。*/
注意:此处查找的字符大小写有区别
strpbrk 函数用于查找任何一组字符第 1 次在字符串中出现的位置。原型如下:
char *strpbrk( char const *str, char const *group );
函数返回一个指向 str 中第 1 个匹配 group 中 任何一个字符 的字符位置。如果未找到匹配,函数返回一个NULL指针。
char string[20] = "Hello there, honey.";
char *ans
ans = strpbrk( string, "aeiou" );
/*ans所指向的位置是string+1。*/
注意:此处查找的字符大小写有区别
strstr 函数用于在字符串中查找一个子串。原型如下:
char *strstr( char const *s1, char const *s2 );
此函数在 s1 中查找整个 s2 第 1 次出现的起始位置,并返回一个指向该位置的指针。
如果 s2 并没有完整地出现在s1的任何地方,就返回一个NULL指针。
标准数据库并不存在 strrstr 或 strrpbrk 函数。可以自己实现。
/*
** 在字符串s1中查找s2最右出现的位置,并返回一个指向该位置的指针
*/
#include
char *my_strrstr( char const *s1, char const *s2 )
{
register char *last;
register char *current;
/*
** 将指针初始化为我们已经找到的前一次匹配位置。
*/
last = NULL;
/*
** 只在第2个字符串不为空时才进行查找,如果s2为空,返回NULL
*/
if( *s2 != '\0' )
{
/*
** 查找s2在s1中第1次出现的位置。
*/
current = strstr( s1, s2 );
/*
** 我们每次找到字符串时,让指针指向它的起始位置,然后查找该字符串下一个匹配位置。
*/
while( current != NULL )
{
last = current;
current = strstr( last + 1, s2 );
}
}
return last;
}
strspn 和 strcspn 函数用于在字符串中的起始位置对字符计数。原型如下:
size_t strspn( char const *str, char const *group );
size_t strcspn( char const *str, char const *group );
group 字符串指定一个或多个字符。
strspn 返回 str 起始部分匹配 group 中任意字符的字符数。
例如:
int len1, len2;
char buffer[] = "25,124,223,Smith,J,3223";
len1 = strspn( buffer, "0123456789" );
len2 = strspn( buffer, ",0123456789" );
/*
** len1 = 2
** len2 = 11
*/
strcspn 函数和 strspn 函数正好相反,它对 str 字符串起始部分中不与 group 中任何字符匹配的字符进行计数。
strtok 函数用于从字符串中隔离各个单独第称为标记的部分,并丢弃分隔符。原型如下:
char *strtok( char *str, char const *sep );
sep 参数是个字符串,定义了用作分隔符的字符集合。
操作系统是通过设置一个外部的 整型变量 errno 进行错误代码报告的。
strerror 函数把其中一个错误代码作为参数并返回一个指向用于描述错误的字符串的指针。原型如下:
char *strerror( int error_number );
标准库定义包含了两组函数,用于操作单独的字符,它们的原型位于头文件 ctype.h。
第1组函数用于对字符分类;
第2组函数用于转换字符。
iscntrl ——任何控制字符、isspace ——空白字符、
isdigit ——十进制数字、isxdigit ——十六进制数字,包括十进制、
islower ——小写字母a~z、isupper ——大写字母A~Z、
isalpha ——字母、isalnum ——字母或数字、
ispunct ——标点符号、isgraph ——任何图形字符、
isprint ——任何可打印字符,包括图形字符和空白字符
转换函数把大写字母转换为小写字母或把小写转换为大写。原型如下:
int tolower( int ch );
int toupper( int ch );
memxxx 函数提供了类似字符串函数的能力,但它们可以处理包括 NUL 字节在内的任意字节。
可以处理任意字的字节序列的函数:
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 *memchr( void const *a, int ch, size_t length );
void *memset( void *a, int ch, size_t length );
每个原型都包含一个显式的参数说明需要处理的字节数,但是它们遇到 NUL 字节时并不会停止操作。
1、memcpy 从 src 的起始位置复制 length 个字节到 dst 的内存起始位置。
2、memmove 函数的行为和 memcpy 差不多,只是它的源和目标操作数是可以重叠的。
3、memcmp 对两段内存的内容进行比较,这两段内存分别起始于a 和 b,共比较 length 个字节。
4、memchr 从 a 的起始位置开始查找字符 ch 第1次出现的位置。
5、memset 函数把从 a 开始的 length 个字节都设置为字符值 ch。