目录
[1. 引言](#1. 引言)
[2. C语言中的字符串与C++ string类的对比](#2. C语言中的字符串与C++ string类的对比)
[3. C++ string类概述](#3. C++ string类概述)
[3.1 string类的构造与初始化](#3.1 string类的构造与初始化)
[3.2 string类的基本操作](#3.2 string类的基本操作)
[3.3 string类的查找和替换](#3.3 string类的查找和替换)
[3.4 string类的遍历](#3.4 string类的遍历)
[4. C++11新特性在string类中的应用](#4. C++11新特性在string类中的应用)
[5. string类的模拟实现](#5. string类的模拟实现)
[5.1 浅拷贝和深拷贝](#5.1 浅拷贝和深拷贝)
[6. 总结与扩展阅读](#6. 总结与扩展阅读)
1. 引言
C++ string
类是用于字符串操作的重要工具之一。相比于C语言中以字符数组形式存储的字符串,C++的string
类在功能和安全性上有了显著提升。由于string
类封装了字符串的存储与操作,我们在使用时不必过多担心底层内存管理问题。这在编程中减少了潜在的内存泄漏与越界访问风险,是现代C++开发的核心之一。
在这篇文章中,我们将深入探讨string
类的各种功能,包括基本操作、常用接口、内部实现机制以及模拟string
类的基本方法,最终让您更深入地理解和掌握string
类的用法和原理。
2. C语言中的字符串与C++ string
类的对比
在C语言中,字符串以字符数组的形式存储,以**\0
** 结尾。C语言的字符串操作依赖于手动管理内存,程序员需要使用诸如**strcpy()
、strcat()
**等函数来操作字符串。
C语言字符串的基本操作:
cpp
#include <stdio.h>
#include <string.h>
int main() {
char str1[20] = "Hello, C!";
char str2[20];
// 字符串复制
strcpy(str2, str1);
printf("str2: %s\n", str2);
// 字符串连接
strcat(str1, " World");
printf("str1: %s\n", str1);
// 字符串长度
printf("Length of str1: %lu\n", strlen(str1));
return 0;
}
问题 :C语言的字符串在操作上较为复杂且容易出错。例如,如果目标数组str2
的空间不足以容纳被复制的内容,程序将面临越界的风险。
在C++中,string
类避免了上述问题,自动管理字符串的内存,支持运算符重载和面向对象的方法调用。C++中的字符串可以这样初始化并操作:
C++ string
类的基本操作:
cpp
#include <iostream>
#include <string>
using namespace std;
int main() {
string str1 = "Hello, C++!";
string str2 = str1; // 拷贝构造
str1 += " Welcome!"; // 字符串拼接
cout << "str1: " << str1 << endl; // 输出 Hello, C++! Welcome!
cout << "str2: " << str2 << endl; // 输出 Hello, C++!
cout << "Length of str1: " << str1.length() << endl;
return 0;
}
C++优势 :在C++中,string
类自动管理内存,同时为字符串操作提供了更加直观和简洁的语法,这些特性极大提高了编程的安全性和开发效率。
3. C++ string
类概述
C++中的string
类支持多种操作,包括字符串的构造、修改、查找和遍历等。
3.1 string
类的构造与初始化
string
类提供了多种构造方法,可以创建空字符串、以C字符串初始化字符串或通过字符和长度创建字符串:
cpp
#include <iostream>
#include <string>
using namespace std;
int main() {
string s1; // 默认构造空字符串
string s2("Hello, C++!"); // 以C字符串初始化
string s3(s2); // 拷贝构造
string s4(5, 'a'); // 构造包含5个字符'a'的字符串 "aaaaa"
cout << "s1: " << s1 << endl; // 输出空字符串
cout << "s2: " << s2 << endl; // 输出 "Hello, C++!"
cout << "s3: " << s3 << endl; // 输出 "Hello, C++!"
cout << "s4: " << s4 << endl; // 输出 "aaaaa"
return 0;
}
3.2 string
类的基本操作
string
类提供了访问、修改字符串的方法,如at()
、push_back()
、append()
、clear()
等。
访问与修改字符:
cpp
string s = "Hello";
cout << s[1] << endl; // 使用[]操作符输出 'e'
cout << s.at(1) << endl; // 使用at()输出 'e',更安全
注意 :at()
方法在访问越界时会抛出异常,而[]
操作符不会,因此在一些严格的场景中at()
更加安全。
添加字符和字符串:
cpp
string s = "Hello";
s.push_back('!'); // 添加单个字符
cout << s << endl; // 输出 "Hello!"
s.append(" World"); // 添加字符串
cout << s << endl; // 输出 "Hello! World"
清空和判断字符串:
cpp
string s = "Hello";
s.clear(); // 清空字符串
cout << s.empty() << endl; // 输出 1 (true) 表示字符串为空
3.3 string
类的查找和替换
查找是string
类中非常常用的操作之一,可以通过find()
、rfind()
来在字符串中搜索特定子串或字符,并使用replace()
替换指定位置的子串:
cpp
string s = "Hello, C++!";
size_t pos = s.find("C++"); // 查找子串"C++"
if (pos != string::npos) {
s.replace(pos, 3, "World"); // 将"C++"替换为"World"
}
cout << s << endl; // 输出 "Hello, World!"
3.4 string
类的遍历
可以使用for
循环或范围for
进行遍历。后者在C++11中引入,使代码更简洁。
cpp
string s = "Hello";
for (char c : s) {
cout << c << ' ';
}
cout << endl; // 输出 H e l l o
4. C++11新特性在string
类中的应用
C++11引入了auto
关键字和范围for
循环,简化了对string
类的使用。
auto关键字 :auto
让编译器自动推断变量类型,在string
类操作中尤为方便。例如在使用迭代器遍历string
时:
cpp
#include <iostream>
#include <string>
using namespace std;
int main() {
string str = "Hello, C++11!";
for (auto it = str.begin(); it != str.end(); ++it) {
cout << *it << ' ';
}
return 0;
}
范围for
循环 :C++11的范围for
使代码更简洁,尤其在遍历和修改字符时。
cpp
string str = "Hello, C++11!";
for (auto& ch : str) {
if (ch == ' ') {
ch = '_';
}
}
cout << str << endl; // 输出 "Hello,_C++11!"
5. string
类的模拟实现
为了更好地理解string
类的内部机制,我们可以模拟实现一个简化版的String
类,重点在于深拷贝 和浅拷贝。
5.1 浅拷贝和深拷贝
浅拷贝:在对象复制时,只复制对象中的指针地址,而不是复制实际内容。这会导致多个对象共享同一块内存。
深拷贝 :在对象复制时,同时复制数据,从而实现每个对象都拥有独立的内存。
浅拷贝示例:
cpp
class String {
public:
String(const char* str = "") {
_str = new char[strlen(str) + 1];
strcpy(_str, str);
}
// 浅拷贝的拷贝构造
String(const String& s) {
_str = s._str;
}
~String() {
delete[] _str;
}
private:
char* _str;
};
在这个例子中,当String
对象销毁时,将导致内存重复释放的问题,因为多个对象共享相同的内存空间。
深拷贝示例:
cpp
class String {
public:
String(const char* str = "") {
_str = new char[strlen(str) + 1
以下是一个简单的String
类模拟,实现了深拷贝以避免资源共享问题:
cpp
#include <iostream>
#include <cstring>
#include <cassert>
using namespace std;
class String {
public:
String(const char* str = "") {
if (str == nullptr) {
_str = new char[1];
*_str = '\0';
} else {
_str = new char[strlen(str) + 1];
strcpy(_str, str);
}
}
// 深拷贝构造函数
String(const String& s) {
_str = new char[strlen(s._str) + 1];
strcpy(_str, s._str);
}
// 深拷贝赋值运算符
String& operator=(const String& s) {
if (this != &s) {
delete[] _str;
_str = new char[strlen(s._str) + 1];
strcpy(_str, s._str);
}
return *this;
}
~String() {
delete[] _str;
}
private:
char* _str;
};
在上述代码中,我们通过自定义的拷贝构造函数和赋值运算符,确保每个String
对象都持有独立的字符串数据,避免了浅拷贝带来的潜在问题。
6. 总结与扩展阅读
C++中的string
类提供了安全、便捷、功能强大的字符串操作接口。掌握string
类有助于提高代码的健壮性,并能大幅减少由内存管理带来的问题。学习string
类的实现和用法,对理解C++标准库以及面向对象编程具有深远意义。