原链接:点击打开链接
偏底层的工程项目中,我们经常会遇到要用C语言来直接处理字符串,了解这些函数,编写起代码来能够事半功倍,这也是字符串处理的基础。C语言直接操作内存,所以需要完全理解这些函数在做什么,并且时刻注意安全检查,才能尽量避免一些奇怪的错误(这也是使用C语言的缺点)。一般地,使用这些函数,需要包含头文件:
#include <string.h>
1. strcpy
原型:char *strcpy (char * __dest, const char * __src);
功能:将一个字符串(__src
)拷贝到另一个字符串缓冲区中(__dest
),并返回拷贝后的字符串指针;
例子:
#include <stdio.h>
#include <string.h>
int main(){
const char* str1 = "abcdefg";
char str2[32];
strcpy(str2,str1);
printf("after copy, str2 = %s\n",str2);
return 0;
}
运行结果:
after copy, str2 = abcdefg
注意:
1. 必须保证拷贝后的缓冲区即上例中str2的大小足够,否则造成内存溢出到未分配的地址,容易产生各种未知错误;
2. 由于该函数原理是逐字节复制,所以如果str1和str2的空间有重叠,则会造成覆盖,可以看下面这个例子:
#include <stdio.h>
#include <string.h>
int main(){
char str1[32]="abcdefg";
strcpy(str1+3,str1);
printf("after copy, str1 = %s\n",str1);
return 0;
}
拷贝后的空间和源字符串的空间是有重合的,则源字符串内容会被修改,运行结果为:
after copy, str1 = abcabcdefg
2. strncpy
原型:char *strncpy (char * __dest, const char *__src, size_t __n);
功能:将一个字符串(__src
)拷贝到另一个字符串缓冲区中(__dest
),拷贝最多不超过__n
字节,并返回拷贝后的字符串指针;
例子:
#include <stdio.h>
#include <string.h>
int main(){
const char* str1 = "allen junyu";
char str2[32]="anything you can write";
char* p=strncpy(str2,str1,7);
printf("p=%s\n",p);
p[7]=0;
printf("p=%s\n",p);
return 0;
}
运行结果:
p=allen jg you can write
p=allen j
注意: strncpy这个函数并不会自动的在字符串结尾加’\0’,需要我们去增加。
3. strcat
原型:char *strcat (char *__dest, const char *__src);
功能:将一个字符串(__src
)拼接到另一个字符串缓冲区中(__dest
),并返回拼接后的字符串指针;
例子:
#include <stdio.h>
#include <string.h>
int main(){
char str1[32] = "allen";
const char* str2 = "junyu";
char* p=strcat(str1,str2);
printf("p=%s\n",p);
return 0;
}
运行结果:
p=allenjunyu
注意:同样地,需要保证str1有足够的存储空间,否则,程序会顺着内存地址往后写,破坏其他内存数据。
4. strncat
原型:char *strncat (char *__dest, const char *__src, size_t __n);
功能:将一个字符串(__src
)拼接到另一个字符串缓冲区中(__dest
),最多不超过__n
个字节,并返回拼接后的字符串指针;
例子:
#include <stdio.h>
#include <string.h>
int main(){
char str1[32]="allen ";
const char* str2="junyu";
strncat(str1,str2,3);
printf("str1=%s,length=%d\n",str1,strlen(str1));
strncat(str1,str2,1000000);
printf("str1=%s,length=%d\n",str1,strlen(str1));
return 0;
}
运行结果:
str1=allen jun,length=9
str1=allen junjunyu,length=14
5. strlen
原型:size_t strlen (const char *__s);
功能:返回一个字符串(__src
)的长度,即字节(符)数,这里仅考虑ASCII字符;
6. strcmp
原型: int strcmp (const char *__s1, const char *__s2);
功能:比较字符串__s1
和字符串__s2
,返回比较结果,如果相等,则返回0;
比较方式:两个字符串自左向右逐个字符相比(按ASCII值大小相比较),直到出现不同的字符或遇’\0’为止;
返回结果:当s1<s2
时,返回值<0;当s1=s2
时,返回值=0;当s1>s2
时,返回值>0;
例子:
#include <stdio.h>
#include <string.h>
int main(){
const char* str1 = "allen junyu";
char str2[32]="allen junyu";
int ret = strcmp(str1,str2);
printf("ret=%d\n",ret);
return 0;
}
运行结果:
ret=0
7. strncmp
原型: int strncmp (const char *__s1, const char *__s2, size_t __n);
功能:比较字符串__s1
和字符串__s2
的__n
个字符,返回比较结果,如果相等,则返回0;
比较方式:同strcmp;
返回结果:同strcmp;
例子:
#include <stdio.h>
#include <string.h>
int main(){
const char* str1 = "allen junyu";
char str2[32]="allen bob";
int ret = strncmp(str1,str2,5);
printf("ret=%d\n",ret);
return 0;
}
运行结果:
ret=0
8. strcasecmp
原型: int strcasecmp (const char *__s1, const char *__s2);
功能:比较字符串__s1
和字符串__s2
,忽略大小写的比较,返回比较结果,如果相等,则返回0;
例子:
#include <stdio.h>
#include <string.h>
int main(){
const char* str1 = "allen";
char str2[32]="AlleN";
int ret = strcasecmp(str1,str2);
printf("strcasecmp ret=%d\n",ret);
return 0;
}
运行结果:
strcasecmp ret=0
9. strncasecmp
原型: int strncasecmp (const char *__s1, const char *__s2, size_t __n);
功能:比较字符串__s1
和字符串__s2
的__n
个字符,忽略大小写的比较,返回比较结果,如果相等,则返回0;
例子:
#include <stdio.h>
#include <string.h>
int main(){
const char* str1 = "allen";
char str2[32]="AlleN junyu";
int ret = strncasecmp(str1,str2,5);
printf("strncasecmp ret=%d\n",ret);
return 0;
}
运行结果:
strncasecmp ret=0
10. strchr
原型:const char *strchr (const char *__s, int __c);
功能:在字符串(__src
)中查找字符__c
首次出现的位置,并返回指向该位置的字符串指针,若没有这个字符,则返回NULL;
例子:
#include <stdio.h>
#include <string.h>
int main(){
const char* str1 = "allen";
const char* p=strchr(str1,'l');
printf("strchr p=%s\n",p);
return 0;
}
运行结果:
strchr p=llen
注意:它只查找第一次出现,并且是返回指向位置的指针,而并不是返回位置;
11. strrchr
原型:const char *strrchr (const char *__s, int __c);
功能:在字符串(__src
)中反向查找字符__c
首次出现的位置,并返回指向该位置的字符串指针,若没有这个字符,则返回NULL;
例子:
#include <stdio.h>
#include <string.h>
int main(){
const char* str1 = "allen";
const char* p=strrchr(str1,'l');;
if(p==NULL){
printf("strrchr p=NULL\n");
}else{
printf("strrchr p=%s\n",p);
}
return 0;
}
运行结果:
strrchr p=len
12. strstr
原型:const char *strstr (const char *__haystack, const char *__needle);
功能:在字符串(__haystack
)中查找字符串__needle
首次出现的位置,并返回指向该位置的字符串指针,若没有这个字符,则返回NULL;
例子:
#include <stdio.h>
#include <string.h>
int main() {
const char* str1 = "allen bigjunyu";
const char* p = strstr(str1, "big");
if (p == NULL) {
printf("strstr p=NULL\n");
} else {
printf("strstr p=%s\n", p);
}
p = strstr(str1, "bigz");
if (p == NULL) {
printf("strstr p=NULL\n");
} else {
printf("strstr p=%s\n", p);
}
return 0;
}
运行结果:
strstr p=bigjunyu
strstr p=NULL
13. strpbrk
原型:const char *strpbrk (const char *__s, const char *__accept);
功能:在字符串(__s
)中查找字符串__needle
中包含的字符集合的任意元素,返回这个任意字符的首次出现的位置,若任何字符,则返回NULL;注意,这个命名很怪异,不像前面的容易记住,这里pbrk的含义应该是”point break”遇到第一个匹配点就返回;
例子:
#include <stdio.h>
#include <string.h>
int main() {
const char* str1 = "allen bigjunyu";
const char* str2 = "zmg";
const char* p = strpbrk(str1, str2);
if (p == NULL) {
printf("strpbrk p=NULL\n");
} else {
printf("strpbrk p=%s\n", p);
}
return 0;
}
运行结果:
strpbrk p=gjunyu
14. strspn
原型:size_t strspn (const char *__s, const char *__accept);
功能:以字符串(__accept
)中字符作为集合,在字符串__s
中查找不属于这个集合的第一个字符的位置并返回,若不存在,则返回整个字符串最后一个字符位置+1;注意,这个命名怪异,这里strspn的含义应该是”string span”的意思;
例子:
#include <stdio.h>
#include <string.h>
int main() {
const char* str1 = "allen junyu";
const char* str2 = "alg";
int idx = strspn(str1, str2);
printf("strspn idx=%d\n",idx);
return 0;
}
运行结果:
strspn idx=3
注意:ubuntu系统上的注释是Return the length of the initial segment of S which consists entirely of characters in ACCEPT.
返回一个初始分割点,使得分割点之前的字符完全由ACCEPT中字符组成,跟上面所述的功能是一样的意思,而且这种注释也好理解一些。
15. strcspn
原型:size_t strcspn (const char *__s, const char *__reject);
功能:以字符串__reject
中字符作为集合,在字符串__s
中查找属于这个集合的第一个字符的位置并返回,若不存在,则返回整个字符串最后一个字符位置+1;可理解为,在__s
中寻找第一个分割点,使得分割点之前的字符串完全由非__reject
中字符组成;
例子:
#include <stdio.h>
#include <string.h>
int main() {
const char* str1 = "allen junyu";
const char* str2 = "xn";
int idx = strcspn(str1, str2);
printf("strcspn idx=%d\n",idx);
return 0;
}
运行结果:
strcspn idx=4
注意:ubuntu系统上的注释是Return the length of the initial segment of S which consists entirely of characters not in REJECT.
15. strsep
原型:char *strsep (char** __stringp, const char* __delim);
功能:以字符串__delim
作为分隔符,在字符串__stringp
寻找分隔符,找到第一个分隔符后,将分隔符位置设置为'\0'
,返回指向分隔符下一个字符,并设置__stringp
所指向的字符串指针的指也指向这个位置,若不存在,则返回NULL;
例子:
#include <stdio.h>
#include <string.h>
int main() {
int len, nel;
char query[] = "user_command=appleboy&test=1&test2=2";
char *q, *name, *value;
q = query;
printf("string is : %s\n", query);
len = strlen(query);
nel = 0;
while (strsep(&q, "&")){
nel++;
printf("now q=%s\n",q);
}
printf("number of elements : %d\n", nel);
int gap;
for (q = query; q < (query + len);) {
printf("pair str :%s\n", q);
value = name = q;
gap = strlen(q)+1;
/* Assign variable */
name = strsep(&value, "=");
printf("key:%s value:%s\n",name,value);
q+=gap;
}
return 0;
}
运行结果:
string is : user_command=appleboy&test=1&test2=2
now q=test=1&test2=2
now q=test2=2
now q=(null)
number of elements : 3
pair str :user_command=appleboy
key:user_command value:appleboy
pair str :test=1
key:test value:1
pair str :test2=2
key:test2 value:2
注意:该函数会更改*__stringp
的值,并且更改原始字符串的值,所以是char*
而非const char*
15. strtok
原型:char *strtok (char* __s, const char* __delim);
功能:以字符串__delim
中字符作为分隔符集合,在字符串__s
中查找,返回由分隔符分割的第一个单词指针,若没有,则返回NULL;当__s
为NULL时,即继续上一次分割;
例子:
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "babybaby&test=1&test2=2";
const char* p;
p = strtok(str, "&=");
printf("str=%s,p=%s\n", str, p);
while (p) {
p = strtok(NULL, "&=");
printf("str=%s,p=%s\n", str, p);
}
return 0;
}
运行结果:
str=babybaby,p=babybaby
str=babybaby,p=test
str=babybaby,p=1
str=babybaby,p=test2
str=babybaby,p=2
str=babybaby,p=(null)
注意:由于该函数具有缓存上次传入字符串的功能,其实是通过一个静态缓冲区来实现,所以是非线程安全的。这个函数在Linux下有线程安全版本strtok_r,更深入的论述,可以参考这篇文章STRTOK函数和STRTOK_R函数。
16. 判断字符的函数集
原型均为:int name (int)
类型 ,返回0表示“否”,其他表示“是”
isalpha() 检查是否为字母字符
isupper() 检查是否为大写字母字符
islower() 检查是否为小写字母字符
isdigit() 检查是否为数字
isxdigit() 检查是否为十六进制数字表示的有效字符
isspace() 检查是否为空格类型字符
iscntrl() 检查是否为控制字符
ispunct() 检查是否为标点符号
isalnum() 检查是否为字母和数字
isprint() 检查是否是可打印字符
isgraph() 检查是否是图形字符,等效于 isalnum() | ispunct()
注意:需要包含的头文件为#include <ctype.h>
17. 数值字符串转成数值型函数集
int atoi(const char* p)
字符串转换到 int 整型 double atof(const char* p)
字符串转换到 double 符点数 long atol(const char* p)
字符串转换到 long 整型
注意:需要包含的头文件为#include <stdlib.h>
,另外,如果是非对应类型的字符串,各自也会返回一个值,所以需要保证是数值字符串,否则无法判断是否正确转换。
18. 字符串转成数值型函数集
原型:double strtod (const char* __nptr, char ** __endptr);
功能:从字符串 __nptr
中转换 double 类型数值,并将后续的字符串指针存储到 __endptr
指向的 char* 类型存储
例子:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main() {
char str[]="123.245junyu";
char buffer[16];
char* p=buffer;
double x=strtod(str,&p);
printf("strtod x=%f,p=%s\n",x,p);
return 0;
}
运行结果:
strtod x=123.245000,p=junyu
原型:long int strtol (const char* __nptr, char** __endptr, int __base);
功能:从字符串__nptr
中转换 long 类型整型数值,__base
显式设置转换的整型进制,设置为 0 以根据特定格式判断所用进制;
例子:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main() {
char str[]="123.goodjunyu";
char buffer[16];
char* p=buffer;
long x=strtol(str,&p,0);
printf("strtol x=%ld,p=%s\n",x,p);
return 0;
}
运行结果:
strtol x=123,p=.goodjunyu
注意:需要包含头文件#include <stdlib.h>
。