C++中C风格字符串与字符数组

时间:2023-01-04 17:25:03

1 字符串字面值与C风格字符串

C++中,双引号括起来的零个或多个字符构成字符串字面值,如

“Hello World”

字符串字面值的类型实际上是由常量构成的数组,编译器在每个字符串的结尾处添加一个空字符(’\0’),因此字符串字面值的实际长度要比它的内容多1

字符串字面值是一种通用结构的实例,这种结构即是C++C继承而来的C风格字符串。C风格字符串不是一种类型,而是为了表达和使用字符串而形成的一种约定俗成的写法。按此习惯书写的字符串存放在字符数组中,并以空字符结束。

2 字符数组

字符数组的详细解释请参考《C++中字符数组》。可以使用字符串字面值对字符数组进行初始化。

char a[] = “C++”;

1字符串字面值与C风格字符串”中提到,字符串字面值的结尾还包含一个空字符,此时数组a的维度是4

3 操作C风格字符串的函数

处理C风格字符串的函数有strlen()strcmp()strcat()以及strcpy()等。这些函数在cstring头文件中定义,cstringC语言头文件string.hC++b版本,因此,在使用这些函数时,应该包含cstring头文件。

#include <cstring>

4 实战

4.1 问题提出

CSDN论坛上有朋友提到如下问题:

char *src = "Danny";

const char *addition = "Andy";

strcat(src, addition);

程序报错,而如果将程序改为

char src[] = "Danny";

const char *addition = "Andy";

strcat(src, addition);

则不报错。

4.2 问题分析

4.2.1 内存结构

C++程序在内存中主要分为五个数据段,分别是代码段、数据段、BBS段、堆和栈。其中,数据段中保存的是全局变量和静态变量,字符串字面值也保存在数据段中;而栈中保存的是程序临时创建的局部变量。

4.1.2 处理数据段中的数据

对于当strcat()函数的两个参数都是字符指针时的情况,此时两个字符指针均指向保存在数据段中的字符串字面值,如图1所示。

C++中C风格字符串与字符数组 

1 srcaddition的内容

从图1中可以看出,字符串字面值”Danny”保存在0x00347838中,而字符串字面值”Andy”保存在0x00347830中。之后通过strcat()函数将”Andy”附加到”Danny”之后,实际上是对程序的数据段进行操作,而程序的数据端是不允许写入的,因此报错信息是“写入位置时发生访问冲突”,如图2所示。

C++中C风格字符串与字符数组 

2 报错信息

4.2.2 处理栈中的数据

如果将src定义为字符数组,则此时src保存在栈中,程序允许对栈中的数据进行修改。src的地址如图3所示。

 C++中C风格字符串与字符数组

3  srcaddition的内容

从图3中可以看出,src的地址是在0x007bf7ec处,该地址位于程序的栈中;而addition的地址是在0x002f7830处,该地址位于程序的数据段中。

此时,虽然strcat()函数不再报错,但是当main()函数返回时,还会弹出栈被破坏的信息,如图4所示。

C++中C风格字符串与字符数组 

4 栈被破坏信息

正如“2 字符数组中提到,数组src的维数是6,使用strcat()函数,将长度为5的字符串字面值“Andy”附加到长度为6src的后面,那么肯定覆盖了程序堆中的其他数据,因此会弹出堆被破坏的信息。

4.3 问题解决

4.3.1 加大strcat()源维数

如果使用处理字符串字面值的函数strcat(),则需要将源即src的数据维数变大,使其大于等于“DannyAndy” 的长度,即不小于10。例如

char src[11] = "Danny";

4.3.2 使用C++string

标准库类型string表示可变长度的字符序列,使用string类型必须首先包含string头文件。

#include <string>

string src = "Danny";

string addition = "Andy";

src += addition;