字符串系列一:C风格字符串
(1)C风格字符串
C风格字符串就是以'\0'结束的字符数组,字符串字面值就是C风格字符串,它以'\0'结尾,类型为const char*。如下面的几个例子:
1 char ca1[] = { 'C','+','+'};//没有'\0'结束符,不是C风格字符串 2 char ca2[] = { 'C','+','+','\0'};//有'\0'结束符,是C风格字符串 3 char ca3[] = "C++";//字符串字面值是C风格字符串,'\0'自动添加 4 char* cpp = "C++";//是C风格字符串 cpp可以指向不同的字符串,但是不能通过cpp修改“C++”,因为它不在栈区,存放在常量存储区,程序结束后由系统释放
5 6 cout<<ca1<<endl;//由于没有'\0'结束符,故而打出来的字符串后面有乱码 7 cout<<ca2<<endl;//ok
(2)C风格字符串标准库函数
C语言标准库提供了一系列处理C风格字符串的库函数,在C++源文件中要使用这些库函数需要包含头文件cstring,cstring头文件是string.h头文件的C++版本,string.h是C语言提供的标准库。
这些库函数要求传入的指针是非零值,所指向的字符数组必须以'\0'结束,具体的库函数主要有以下几种:
库函数 | 功能 |
strlen(s) | 反复字符串s的长度,不包含'\0'结束符 |
strcmp(s1,s2) | 比较字符串的大小。若s1>s2,返回正数;若s1=s2,返回0;若s1<s2,返回负数 |
strcat(s1,s2) | 将字符串s2连接到s1,并返回s1 |
strcpy(s1,s2) | 将s2复制给s1,并返回s1 |
strncat(s1,s2,n) | 将s2的前n个字符连接到s1,并返回s1 |
strncpy(s1,s2,n) | 将s2的前n个字符复制给s1,并返回s1 |
C++语言提供普通的关系操作符实现标准库类型string的对象比较,这些操作符也可用于比较指向C风格字符串的指针,但效果不同,此时比较的是指针中存放的地址,而非字符数组。C风格字符串的比较须利用strcmp标准库函数。
(3)字符串数组必须要有'\0'结束符
C语言提供的处理C风格字符串标准库函数要求字符串必须有'\0'结束符,否则处理结果无法预料,比如函数strlen,它假定要处理的字符串有'\0'结束符,从指针指向的第一个地址开始计数直到遇到'\0'结束符,然后返回这段内存中的字符个数,如果给定的字符不含'\0'结束符,那么结果是随机的,不可预料的。
(4)标准库函数要求目标字符串必须有足够的大小
对于标准库函数strcat和strcpy,第一个实参数组都应具备足够大的空间来容纳新生成的字符串,否则至少在VS2010环境下执行之后会报运行时错误。
相比于strcat和strcpy而言,使用能够控制字符个数的strncpy和strncat更安全,但要时刻记住为'\0'字符预留空间。
在使用C语言提供的标准库函数处理C风格字符串时,需要留意空间是否足够,是否会发生溢出等问题。而C++标准库类型string则不存在这方面的问题,标准库负责处理内存管理问题,因此增强了安全性,也提高了效率。
(5)strcat和strcpy函数实现
1 char* strcat(char* dest, const char* src) 2 { 3 assert((dest != NULL) && (src != NULL)); 4 char* addr = dest; 5 while(*dest) 6 { 7 dest++; 8 } 9 while((*dest++ = *src++) != '\0') 10 ; 11 return addr; 12 } 13 14 char* strcpy(char* dest, const char* src) 15 { 16 assert((dest != NULL) && (src != NULL)); 17 char* addr = dest; 18 while((*dest++ = *src++) != '\0') 19 ; 20 return addr; 21 }
注意:dest字符串必须要有足够的内存空间来容纳新生成的字符串,否则即使得到结果程序也会报错。