本文试着比较c++字符串与C风格字符串,主要讨论的是c++中的字符串的简单操作。
1、C风格字符串的主要操作与缺陷;
主要操作有: strlen (求长度)、strcpy(复制字符串) 、strcmp(比较字符串大小)、strcat(字符串连接)、strstr(寻找子字符串)
C标准库实现:
char str1[20] = "hello"; //必须有足够大的容量。
char str2[6] = "world!";
1)、strcat
str1 = strcat (str1 ,str2);//将str1末尾的 ' ‘用str2 中的 ' w '替换 。并在新的 str1 末尾自动添加 ’ ‘ 。
//strcat函数返回的是 新的str1 的首地址
2)、strlen //统计字符串中字符的个数 ,而不将 ‘ ’计入
strlen(str2) = 6 ;
sizeof(str2) = 7 ;
C风格字符串缺陷:
1)、结束符 ' 0 ';
2)、很多时候需要自行保证安全性,例如下面的代码很容易让程序崩溃
#include<iostream> #include<string.h> using namespace std ; int main(int argc ,char *argv[]) { char buf[3] ; strcpy(buf ,"hello"); cout << buf << endl ; }
这里错误的原因在于buf 的内存不够 ,产生内存越界,但是 strcpy 不会也无法检测内存是否越界。
C++ 的解决方案是引入了string类型,我们稍后叙述。
这里再叙述很多同学在自己实现字符串的一系列函数中出现的错误以及原因,代码如下;
1 #include<iostream> 2 #include<string.h> 3 using namespace std ; 4 5 char *strcat(char *s1 ,const char* s2) 6 { 7 s1 = (char*)malloc( strlen(s1) + strlen(s2) ); 8 } 9 10 char* strcppy(char*s1 , const char* s2) 11 { 12 s1 = (char*)malloc( strlen(s2) ); 13 } 14 15 int main(int argc ,char *argv[]) 16 { 17 char p[128] ; 18 19 strcat( p ,"hello"); 20 21 return 0 ; 22 }
上述代码的错误之处:
1)、我们姑且不管malloc分配内存的大小(当然此处分配的大小肯定是不够的)。
首先对 s1进行重新分配内存显然是无效的,当main函数执行到strcat时 ,会调用strcat函数,然而在strcat函数中 s1 的任何改动都与 p 无关 。因为我们知道C语言中的 参数传递 是 值拷贝(以后会详细叙述)。这实际上造成了内存泄露。
2)、就算这里能够改变 p 的指向,这样的做法也是不允许的。因为这会使得其他地方的字符串失效。当然这里不太可能。不做额外讨论。
2、C++字符串的实现
相对于C,C++提供了一种类型 string,可以更加简单更加安全的操作字符串。代码如下:
#include <iostream> #include <string> #include <vector> using namespace std; int main(int argc ,char*argv[]) { string s1 = "hello "; string s2("test"); //赋值 string s3 ; //空字符串 cout << s1 << endl ; //打印 cout << s1,size() << endl ;//求长度 s3 = s1 ;//字符串的复制 s3 += s2 ;//OK!字符串的拼接strcat s3 = "hello" + "world" + s1 ; // error 右结合性 char*和char* 不可相加 s3 = s1 + "hello " + "world" ; //ok 右结合性 ,先计算s1+“hello”生成新的str cout << s3 << endl ; //比较大小 cout << (s1 > s2) << endl ; cout << (s1 == s3) << endl ; return 0 ; }
string 同样支持下标操作 和 迭代器操作(可以理解成指针 ,以后详细叙述),代码如下:
//下标操作 for(size_t ix = 0 ;ix != s.size() ; ++ ix) { cout << s[ix] << " " ; } cout << endl ;
//迭代器操作 for (string::iterator it = s3.begin() ;//指向容器的第一个位置 it != s3.end(); // 指向容器最后一个元素的下一个位置
it++ ) { cout << *it << " " ; } cout << endl ;
一下代码实现的是字符串的查找(查找单词的情况与此一样 ,我们就不再赘述):
//查找单个字符 int main(int argc ,char *argv[]) { string str ; getline(cin ,str); // 读入字符串 ,遇见空格或者enter键表示输入结束 char ch ; while(cin >> ch) { string::size_type pos = s.find(ch) ; if( pos != string::npos )//search success { cout << pos << endl ;// 下标 }else // false { cout << "find failure!" << endl ; } } return 0 ; }
最后 ,string 可以转化为C风格字符串:
//转化为C风格字符串 string s = "shenzhen" ; cout << s.c_str() << endl ;
注意:
1)、string 得出的 char* 是const(只读)属性 ,不可对其修改 ;
2)、另外,这个值可能失效,所以,如果需要,最好每次调用 s.c_str() ;