【c++语言程序设计】字符串与浅层复制(深拷贝与浅拷贝)
字符串常量是用一对双引号括起来的字符序列,例如,"abcd" " China"" This is a string." 都是字符串常量。它在内存中的存放形式是,按串中字符的排列次序顺序存放,每个字符占1字节,并在末尾添加'\0'作为结尾标记
字符串常量指针
这实际上是一个隐含创建的类型为 char的数组,一个字符串常量就表示这样一个数组的首地址。
const char *STRING1 = "This is a string.";
它是一个常量字符串,无法通过 STRING1
修改字符串内容
字符数组
字符串变量也可以用类似方式来表示。如果创建一个 char数组,每个元素存放字符串的一个字符,在末尾放置一个'\0',便构成了C++字符串。
在定义用于存放字符串的字符数组时,数组长度应至少为字符串字符数加1(用于存储结尾的 '\0'
)
char str[8] = {'p', 'r', 'o', 'g', 'r', 'a', 'm', '\0'};
char str[8] = "program";
char str[] = "program";
它的存储方式与字符串常量无异,但由于它是程序员创建的数组,因此可以改写其内容,因而这就是字符串变量而非常量
- 数组大小:定义字符数组的长度时,大小应至少为字符串长度加1。
'\0'
结尾:字符串结尾'\0'
是必须的,否则字符串操作函数(如strlen
、strcpy
等)无法正确判断字符串结束。- 字符串可修改:字符数组
str
是变量,可以直接修改其内容,而字符串常量不允许这样操作。
尽管对用字符数组表示的字符串进行初始化还比较容易、直观,但进行许多其他字符串操作时却比较麻烦。执行很多字符串操作需要借助 cstring头文件中的字符串处理函数,例如将一个字符串的内容复制到另一个字符串需要用 strepy函数,按辞典顺序比较两个的大小需要用 strcmp函数,将两个字符串连接起来需要用 strcat函数。另外,当字符串长度很不确定时,需要用 new 动态创建字符数组,最后还要用 delete释放,这些都相当烦琐。
string 类
数组数据与处理数据的函数分离也不符合面向对象方法的要求。
C++标准类库将面向对象的串的概念加入到C++语言中,预定义了字符串类( string类),string类提供了对字符串进行处理所需要的操作。使用 string类需要包含头文件 string。string类封装了串的属性并提供了一系列允许访问这些属性的函数。
string
类的构造函数
-
string()
:默认构造函数,创建一个长度为0的字符串。 -
string(const string& rhs)
:复制构造函数,用已有的string
对象初始化新的string
对象。 -
string(const char* s)
:使用指向字符串常量的指针*s
初始化string
对象。 -
string(const string& rhs, unsigned int pos, unsigned int n)
:从rhs
对象的pos
位置开始提取n
个字符,用它们初始化新的string
对象。 -
string(const char* s, unsigned int n)
:使用指针s
所指字符串的前n
个字符初始化string
对象。 -
string(unsigned int n, char c)
:将字符c
重复n
次,用于初始化string
对象
由于
string
类接收const char*
类型的构造函数,字符串常量和字符数组都可以隐式转换为string
对象。string str = "Hello world!";
string
类的操作符
string
类重载了许多操作符,支持赋值、连接、比较等功能
操作符 | 示例 | 功能说明 |
+ | s + t | 将字符串s和t连接成新串 |
= | s = t | 用t更新s |
+= | s += t | 等价于s = s + t |
== | s == t | 判断s和t是否相等 |
!= | s != t | 判断s和t是否不等 |
< | s < t | 判断s是否小于t(字典顺序) |
<= | s <= t | 判断s是否小于或等于t |
> | s > t | 判断s是否大于t |
>= | s >= t | 判断s是否大于或等于t |
[ ] | s[i] | 访问字符串s中下标i的字符 |
字符串的大小比较是按字典顺序进行,遵循以下规则:
- 如果两串长度和内容都相同,则
==
。- 如果第一个不相同字符的ASCII码较小,则对应的字符串较小。
- 如果一串是另一串的前缀,则前缀串较小。
常用成员函数
以下是一些string
类的常用成员函数:
-
追加:
string append(const char* s)
:将字符串s
追加到本串尾部。 -
赋值:
string assign(const char* s)
:将s
赋值给本对象。 -
比较:
int compare(const string& str) const
:比较本字符串和str
的大小。 -
插入:
string& insert(unsigned int p0, const char* s)
:将s
插入到本串的p0
位置前。 -
取子串:
string substr(unsigned int pos, unsigned int n) const
:返回从pos
位置开始的n
个字符的子串。 -
查找:
unsigned int find(const basic_string& str) const
:查找并返回str
第一次在本串中出现的位置。 -
获取长度:
unsigned int length() const
:返回字符串的长度(字符个数)。 -
交换:
void swap(string& str)
:交换本字符串和str
的内容。
#include <string>
#include <iostream>
using namespace std;// 根据 value 的值输出 true 或 false,title 为提示文字
inline void test(const char *title, bool value) {cout << title << " returns " << (value ? "true" : "false") << endl;
}int main() {string s1 = "DEF";cout << "s1 is " << s1 << endl;string s2;cout << "Please enter s2: ";cin >> s2; // 输入字符串 s2cout << "length of s2: " << s2.length() << endl; // 输出 s2 的长度// 比较运算符的测试test("s1 <= \"ABC\"", s1 <= "ABC"); // 判断 s1 是否小于等于 "ABC"test("\"DEF\" <= s1", "DEF" <= s1); // 判断 "DEF" 是否小于等于 s1// 连接运算符的测试s2 += s1; // 将 s1 连接到 s2 的末尾cout << "s2 = s2 + s1: " << s2 << endl;cout << "length of s2: " << s2.length() << endl; // 输出连接后的 s2 的长度return 0;
}
getline
函数
getline
函数是用于从输入流中读取字符串的函数,在C++中,常用于从cin
或文件中获取一行字符串。
-
getline
不会忽略开头的空白字符(空格、制表符等),直接将其作为内容的一部分。 -
getline
读取结束后,分隔符本身不会包含在字符串中,但会从输入流中移除
#include <iostream>
#include <string>
using namespace std;int main() {for (int i = 0; i < 2; i++) {string city, state;// 以逗号为分隔符读取城市名称getline(cin, city, ',');// 读取国家/地区名称,直到行尾getline(cin, state);cout << "City: " << city << " State: " << state << endl;}return 0;
}
使用场景
读取整行文本:适用于读取包含空格的完整句子,如从用户输入中获取一行完整文本。
自定义分隔:适合处理结构化文本输入,指定分隔符来分割输入内容,例如CSV文件的逐行读取