返回介绍

4.3 string 类简介

发布于 2024-10-08 23:14:02 字数 7511 浏览 0 评论 0 收藏 0

ISO/ANSI C++98 标准通过添加 string 类扩展了 C++库,因此现在可以 string 类型的变量(使用 C++的话说是对象)而不是字符数组来存储字符串。您将看到,string 类使用起来比数组简单,同时提供了将字符串作为一种数据类型的表示方法。

要使用 string 类,必须在程序中包含头文件 string。string 类位于名称空间 std 中,因此您必须提供一条 using 编译指令,或者使用 std::string 来引用它。string 类定义隐藏了字符串的数组性质,让您能够像处理普通变量那样处理字符串。程序清单 4.7 说明了 string 对象与字符数组之间的一些相同点和不同点。

程序清单 4.7 strtype1.cpp

下面是该程序的运行情况:

从这个示例可知,在很多方面,使用 string 对象的方式与使用字符数组相同。

  • 可以使用 C-风格字符串来初始化 string 对象。
  • 可以使用 cin 来将键盘输入存储到 string 对象中。
  • 可以使用 cout 来显示 string 对象。
  • 可以使用数组表示法来访问存储在 string 对象中的字符。

程序清单 4.7 表明,string 对象和字符数组之间的主要区别是,可以将 string 对象声明为简单变量,而不是数组:

类设计让程序能够自动处理 string 的大小。例如,str1 的声明创建一个长度为 0 的 string 对象,但程序将输入读取到 str1 中时,将自动调整 str1 的长度:

这使得与使用数组相比,使用 string 对象更方便,也更安全。从理论上说,可以将 char 数组视为一组用于存储一个字符串的 char 存储单元,而 string 类变量是一个表示字符串的实体。

4.3.1 C++11 字符串初始化

正如您预期的,C++11 也允许将列表初始化用于 C-风格字符串和 string 对象:

4.3.2 赋值、拼接和附加

使用 string 类时,某些操作比使用数组时更简单。例如,不能将一个数组赋给另一个数组,但可以将一个 string 对象赋给另一个 string 对象:

string 类简化了字符串合并操作。可以使用运算符+将两个 string 对象合并起来,还可以使用运算符+=将字符串附加到 string 对象的末尾。继续前面的代码,您可以这样做:

程序清单 4.8 演示了这些用法。可以将 C-风格字符串或 string 对象与 string 对象相加,或将它们附加到 string 对象的末尾。

程序清单 4.8 strtype2.cpp

转义序列\"表示双引号,而不是字符串结尾。该程序的输出如下:

4.3.3 string 类的其他操作

在 C++新增 string 类之前,程序员也需要完成诸如给字符串赋值等工作。对于 C-风格字符串,程序员使用 C 语言库中的函数来完成这些任务。头文件 cstring(以前为 string.h)提供了这些函数。例如,可以使用函数 strcpy( ) 将字符串复制到字符数组中,使用函数 strcat( ) 将字符串附加到字符数组末尾:

程序清单 4.9 对用于 string 对象的技术和用于字符数组的技术进行了比较。

程序清单 4.9 strtype3.cpp

下面是该程序的输出:

处理 string 对象的语法通常比使用 C 字符串函数简单,尤其是执行较为复杂的操作时。例如,对于下述操作:

使用 C-风格字符串时,需要使用的函数如下:

另外,使用字符数组时,总是存在目标数组过小,无法存储指定信息的危险,如下面的示例所示:

函数 strcat( ) 试图将全部 12 个字符复制到数组 site 中,这将覆盖相邻的内存。这可能导致程序终止,或者程序继续运行,但数据被损坏。string 类具有自动调整大小的功能,从而能够避免这种问题发生。C 函数库确实提供了与 strcat( ) 和 strcpy( ) 类似的函数—strncat( ) 和 strncpy( ),它们接受指出目标数组最大允许长度的第三个参数,因此更为安全,但使用它们进一步增加了编写程序的复杂度。

下面是两种确定字符串中字符数的方法:

函数 strlen( ) 是一个常规函数,它接受一个 C-风格字符串作为参数,并返回该字符串包含的字符数。函数 size( ) 的功能基本上与此相同,但句法不同:str1 不是被用作函数参数,而是位于函数名之前,它们之间用句点连接。与第 3 章介绍的 put( ) 方法相同,这种句法表明,str1 是一个对象,而 size( ) 是一个类方法。方法是一个函数,只能通过其所属类的对象进行调用。在这里,str1 是一个 string 对象,而 size( ) 是 string 类的一个方法。总之,C 函数使用参数来指出要使用哪个字符串,而 C++ string 类对象使用对象名和句点运算符来指出要使用哪个字符串。

4.3.4 string 类 I/O

正如您知道的,可以使用 cin 和运算符<<来将输入存储到 string 对象中,使用 cout 和运算符<<来显示 string 对象,其句法与处理 C-风格字符串相同。但每次读取一行而不是一个单词时,使用的句法不同,程序清单 4.10 说明了这一点。

程序清单 4.10 strtype4.cpp

下面是一个运行该程序时的输出示例:

在用户输入之前,该程序指出数组 charr 中的字符串长度为 27,这比该数组的长度要大。这里要两点需要说明。首先,为初始化的数组的内容是未定义的;其次,函数 strlen( ) 从数组的第一个元素开始计算字节数,直到遇到空字符。在这个例子中,在数组末尾的几个字节后才遇到空字符。对于未被初始化的数据,第一个空字符的出现位置是随机的,因此您在运行该程序时,得到的数组长度很可能与此不同。

另外,用户输入之前,str 中的字符串长度为 0。这是因为未被初始化的 string 对象的长度被自动设置为 0。

下面是将一行输入读取到数组中的代码:

这种句点表示法表明,函数 getline( ) 是 istream 类的一个类方法(还记得吗,cin 是一个 istream 对象)。正如前面指出的,第一个参数是目标数组;第二个参数数组长度,getline( ) 使用它来避免超越数组的边界。

下面是将一行输入读取到 string 对象中的代码:

这里没有使用句点表示法,这表明这个 getline( ) 不是类方法。它将 cin 作为参数,指出到哪里去查找输入。另外,也没有指出字符串长度的参数,因为 string 对象将根据字符串的长度自动调整自己的大小。

那么,为何一个 getline( ) 是 istream 的类方法,而另一个不是呢?在引入 string 类之前很久,C++就有 istream 类。因此 istream 的设计考虑到了诸如 double 和 int 等基本 C++数据类型,但没有考虑 string 类型,所以 istream 类中,有处理 double、int 和其他基本类型的类方法,但没有处理 string 对象的类方法。

由于 istream 类中没有处理 string 对象的类方法,因此您可能会问,下述代码为何可行呢?

像下面这样的代码使用 istream 类的一个成员函数:

但前面处理 string 对象的代码使用 string 类的一个友元函数。有关友元函数及这种技术为何可行,将在第 11 章介绍。另外,您可以将 cin 和 cout 用于 string 对象,而不用考虑其内部工作原理。

4.3.5 其他形式的字符串字面值

本书前面说过,除 char 类型外,C++还有类型 wchar_t;而 C++11 新增了类型 char16_t 和 char32_t。可创建这些类型的数组和这些类型的字符串字面值。对于这些类型的字符串字面值,C++分别使用前缀 L、u 和 U 表示,下面是一个如何使用这些前缀的例子:

C++11 还支持 Unicode 字符编码方案 UTF-8。在这种方案中,根据编码的数字值,字符可能存储为 1~4 个八位组。C++使用前缀 u8 来表示这种类型的字符串字面值。

C++11 新增的另一种类型是原始(raw)字符串。在原始字符串中,字符表示的就是自己,例如,序列\n 不表示换行符,而表示两个常规字符—斜杠和 n,因此在屏幕上显示时,将显示这两个字符。另一个例子是,可在字符串中使用",而无需像程序清单 4.8 中那样使用繁琐的\"。当然,既然可在字符串字面量包含",就不能再使用它来表示字符串的开头和末尾。因此,原始字符串将"(和)"用作定界符,并使用前缀 R 来标识原始字符串:

上述代码将显示如下内容:

如果使用标准字符串字面值,将需编写如下代码:

在上述代码中,使用了\来显示\,因为单个\表示转义序列的第一个字符。

输入原始字符串时,按回车键不仅会移到下一行,还将在原始字符串中添加回车字符。

如果要在原始字符串中包含)",该如何办呢?编译器见到第一个)"时,会不会认为字符串到此结束?会的。但原始字符串语法允许您在表示字符串开头的"和(之间添加其他字符,这意味着表示字符串结尾的"和) 之间也必须包含这些字符。因此,使用 R"+*(标识原始字符串的开头时,必须使用)+*"标识原始字符串的结尾。因此,下面的语句:

将显示如下内容:

总之,这使用"+*(和)+*"替代了默认定界符"(和)"。自定义定界符时,在默认定界符之间添加任意数量的基本字符,但空格、左括号、右括号、斜杠和控制字符(如制表符和换行符)除外。

可将前缀 R 与其他字符串前缀结合使用,以标识 wchar_t 等类型的原始字符串。可将 R 放在前面,也可将其放在后面,如 Ru、UR 等。

下面介绍另一种复合类型—结构。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文