设为首页 加入收藏

TOP

3.5.4 C风格字符串
2013-10-07 16:28:16 来源: 作者: 【 】 浏览:94
Tags:3.5.4 风格 字符串

3.5.4  C风格字符串

尽管C++(www.cppentry.com)支持C风格字符串,但在C++(www.cppentry.com)程序中最好还是不要使用它们。这是因为C风格字符串不仅使用起来不太方便,而且极易引发程序漏洞,是诸多安全问题的根本原因。

字符串字面值是一种通用结构的实例,这种结构即是C++(www.cppentry.com)由C继承而来的C风格字符串(C-style character string)。C风格字符串不是一种类型,而是为了表达和使用字符串而形成的一种约定俗成的写法。按此习惯书写的字符串存放在字符数组中并以空字符结束(null terminated)。以空字符结束的意思是在字符串最后一个字符后面跟着一个空字符('\0')。一般利用指针来操作这些字符串。

C标准库String函数

表3.8列举了C语言标准库提供的一组函数,这些函数可用于操作C风格字符串,它们定义在cstring头文件中,cstring是C语言头文件string.h的C++(www.cppentry.com)版本。

表3.8:C风格字符串的函数

3.8C风格字符串的函数

strlen(p)

返回p的长度,空字符不计算在内

strcmp(p1, p2)

比较p1p2的相等性。如果p1==p2

返回0;如果p1>p2,返回一个正值;

如果p1<p2,返回一个负值

strcat(p1, p2)

p2附加到p1之后,返回p1

strcpy(p1, p2)

p2拷贝给p1,返回p1

表3.8所列的函数不负责验证其字符串参数。

传入此类函数的指针必须指向以空字符作为结束的数组:

  1. char ca[] = {'C', '+', '+'};    // 不以空字符结束  
  2. cout << strlen(ca) << endl;         // 严重错误:ca没有以空字符结束 

此例中,ca虽然也是一个字符数组但它不是以空字符作为结束的,因此上述程序将产生未定义的结果。strlen函数将有可能沿着ca在内存中的位置不断向前寻找,直到遇到空字符才停下来。

比较字符串

比较两个C风格字符串的方法和之前学习过的比较标准库string对象的方法大相径庭。比较标准库string对象的时候,用的是普通的关系运算符和相等性运算符:
 

  1. string s1 = "A string example";  
  2. string s2 = "A different string";  
  3. if (s1 < s2) // false:s2小于s1  

如果把这些运算符用在两个C风格字符串上,实际比较的将是指针而非字符串本身:

  1. const char ca1[] = "A string example";  
  2.     const char ca2[] = "A different string";  
  3.     if (ca1 < ca2)  // 未定义的:试图比较两个无关地址  


谨记之前介绍过的,当使用数组的时候其实真正用的是指向数组首元素的指针(参见3.5.3节,第117页)。因此,上面的if条件实际上比较的是两个const char*的值。这两个指针指向的并非同一对象,所以将得到未定义的结果。

要想比较两个C风格字符串需要调用strcmp函数,此时比较的就不再是指针了。如果两个字符串相等,strcmp返回0;如果前面的字符串较大,返回正值;如果后面的字符串较大,返回负值:

  1. if (strcmp(ca1, ca2) < 0) // 和两个string对象的比较 s1 < s2效果一样 

目标字符串的大小由调用者指定

连接或拷贝C风格字符串也与标准库string对象的同类操作差别很大。例如,要想把刚刚定义的那两个string对象s1和s2连接起来,可以直接写成下面的形式:
 

  1. // 将largeStr初始化成s1、一个空格和s2的连接  
  2. string largeStr = s1 + " " + s2; 

同样的操作如果放到ca1和ca2这两个数组身上就会产生错误了。表达式ca1 + ca2试图将两个指针相加,显然这样的操作没什么意义,也肯定是非法的。

正确的方法是使用strcat函数和strcpy函数。不过要想使用这两个函数,还必须提供一个用于存放结果字符串的数组,该数组必须足够大以便容纳下结果字符串及末尾的空字符。下面的代码虽然很常见,但是充满了安全风险,极易引发严重错误:

  1. // 如果我们计算错了largeStr的大小将引发严重错误  
  2. strcpy(largeStr, ca1);      // 把ca1拷贝给largeStr  
  3. strcat(largeStr, " ");      // 在largeStr的末尾加上一个空格  
  4. strcat(largeStr, ca2);      // 把ca2连接到largeStr后面  

一个潜在的问题是,我们在估算largeStr所需的空间时不容易估准,而且largeStr所存的内容一旦改变,就必须重新检查其空间是否足够。不幸的是,这样的代码到处都是,程序员根本没法照顾周全。这类代码充满了风险而且经常导致严重的安全泄漏。

对大多数应用来说,使用标准库string要比使用C风格字符串更安全、更高效。

3.5.4节练习

练习3.37:下面的程序是何含义,程序的输出结果是什么?
 

  1. const char ca[] = {’h’, ’e’, ’l’, ’l’, ’o’};  
  2.     const char *cp = ca;  
  3.     while (*cp) {  
  4.         cout << *cp << endl;  
  5.         ++cp;  
  6.     }  

练习3.38:在本节中我们提到,将两个指针相加不但是非法的,而且也没什么意义。请问为什么两个指针相加没什么意义?

练习3.39:编写一段程序,比较两个string对象。再编写一段程序,比较两个C风格字符串的内容。

练习3.40:编写一段程序,定义两个字符数组并用字符串字面值初始化它们;接着再定义一个字符数组存放前两个数组连接后的结果。使用strcpy和strcat把前两个数组的内容拷贝到第三个数组中。
 

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇3.5.3 指针和数组(3) 下一篇3.5.5 与旧代码的接口

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: