32.面向对象关联知识点-字符数组和string
32.1 知识点
知识回顾:字符数组
- 字符数组就是类型为字符
char
的一维数组 - 聚合初始化与单独初始化方式
- 直接将字符数组打印可能出现问题
- 使用字符串字面量赋值时,会在尾部自动添加
\0
作为结束符 - 未初始化的元素在打印时可能产生未定义行为
// 方式一:聚合初始化
char charArr[5] = { 'H', 'E', 'L', 'L', 'O' };
char charArr2[] = { 'H', 'E', 'L', 'L', 'O' };
// 方式二:单独初始化
char charArr3[5];
charArr3[0] = 'H';
charArr3[1] = 'E';
// 直接打印会出问题
// 可以使用字符串对字符数组进行赋值
char charArr4[] = "Hellow World"; // string
cout << charArr4 << endl;
// 原本看起来只有12个字符的字符串,但是长度却有13个
int length = sizeof(charArr4) / sizeof(char);
cout << length << endl;
// 对字符数组用字符串去赋值时,会默认在尾部加上一个 '\0' 的转义字符,代表字符串的结束
char charArr5[5];
charArr5[0] = 'A';
charArr5[1] = 'B';
// charArr5[2] = 'X';
// charArr5[3] = 'C';
// charArr5[4] = '\0';
// 如果不对字符数组后面的内容进行初始化,并且其中没有 '\0',
// 在打印时就不知道何时结束,就会不停地往后读取。
// 因为没有明确的终止符,程序会根据内存中是否存在 '\0' 停止打印,
// 可能打印出多余字符,甚至是乱码,产生未定义行为
cout << charArr5[2] << endl;
cout << charArr5 << endl;
// 关于“烫”字符
// 在内存中,汉字使用多字节编码(如 UTF-8 或 GBK)
// 当程序读取到这些内存内容时,会尝试解释它们
// 可能形成合法的汉字编码,导致控制台上显示出汉字或其他非预期字符
cout << "****************************" << endl;
字符数组公共方法
- C++ 中内置了一些关于字符数组的 C 语言方法
strcat_s
、strcpy_s
、strcmp
、strlen
等函数的使用规则相同:目标长度不足会报错
// 1. strcat_s(字符数组, 字符数组长度, 字符串)
// 将一个字符串连接到另一个字符数组中
// 操作前:str1 = "123"(长度3),str2 = "456"(长度3),str1 可用空间为7(sizeof(str1)=10)
char str1[10] = "123";
char str2[10] = "456";
strcat_s(str1, sizeof(str1), str2);
cout << str1 << endl; // 输出:123456
// 2. strcpy_s(字符数组, 字符数组长度, 字符串)
// 将一个字符串复制到另一个字符数组中
// 操作前:str1 = "123456"(长度6),目标"7777777"(长度7),str1 可用空间为4
strcpy_s(str1, sizeof(str1), "7777777");
cout << str1 << endl; // 输出:7777777
// 3. strcmp(字符数组1, 字符数组2)
// 比较两个字符数组是否相同,0 代表相同,非0代表不同
cout << strcmp(str1, "7777777") << endl; // 输出:0
// 4. strlen(字符数组)
// 得到字符数组实际长度(不包含 '\0')
cout << strlen(str1) << endl; // 输出:7
string 相关方法
- C++
string
类提供更丰富、更安全的字符串操作 - 可使用
+
、append
、size
/length
、empty
、clear
、capacity
等成员函数
// 1. 拼接
string string1 = "123";
string string2 = "456";
string1.append(string2);
cout << string1 << endl; // 输出:123456
// 2. 返回字符串长度
cout << string1.size() << endl; // 输出:6
cout << string1.length() << endl; // 输出:6
// 3. 判断字符串是否为空
string string3 = "1";
cout << string3.empty() << endl; // 输出:0(false)
// 4. 清空字符串
string3.clear();
cout << string3 << endl; // 输出:(空字符串)
// 5. 返回容量
string3 = "1234567890123456789";
cout << string3.capacity() << endl; // 输出:31(不同环境可能不同)
// 6. 在指定位置插入字符串
string3.insert(1, "哈哈");
cout << string3 << endl; // 输出:1哈哈234567890123456789
string3.insert(23, "嘻嘻嘻");
cout << string3 << endl; // 输出:1哈哈234567890123456789嘻嘻嘻
// 7. 从指定索引位置起删除固定个数字符
cout << string3.size() << endl; // 输出:26
string3.erase(23, 6); // 修正:原索引29超出范围
cout << string3 << endl; // 输出:1哈哈234567890123456789
// 8. 替换指定区间为另一个字符串
string3.replace(0, 10, "123456");
cout << string3 << endl; // 输出:12345667890123456789
// 9. 交换两个字符串
cout << string1 << endl; // 输出:123456
cout << string2 << endl; // 输出:456
string1.swap(string2);
cout << string1 << endl; // 输出:456
cout << string2 << endl; // 输出:123456
// 10. 删除最后一个字节(注意多字节字符问题)
string3.push_back('1');
cout << string3 << endl; // 输出:123456678901234567891
string3.pop_back();
cout << string3 << endl; // 输出:12345667890123456789
// 11. 添加单个字符
string3.push_back('A');
cout << string3 << endl; // 输出:12345667890123456789A
// 12. 查找字符串第一次出现的位置(找不到返回 -1)
string string4 = "12345627";
int i = string4.find("2");
cout << i << endl; // 输出:1
// 13. 查找最后一次出现的位置
i = string4.rfind("2");
cout << i << endl; // 输出:6
// 14. 查找首次/最后一次出现在传入字符串中的任一字符
string4 = "12345627";
i = string4.find_first_of("478");
cout << i << endl; // 输出:3
i = string4.find_last_of("478");
cout << i << endl; // 输出:7
// 15. 查找第一个/最后一个不在传入字符串中的字符
i = string4.find_first_not_of("12367");
cout << i << endl; // 输出:3
i = string4.find_last_not_of("2367");
cout << i << endl; // 输出:4
// 16. 截取字符串
string4 = "12345627";
string string5 = string4.substr(1, 4);
cout << string5 << endl; // 输出:2345
// 17. 字符串转字符数组
const char* charPtr = string4.data();
for (int i = 0; i < string4.size(); i++)
{
cout << charPtr[i] << endl; // 逐行输出:1 2 3 4 5 6 2 7
}
// 18. 判断字符串内容是否相等
string1 = "123";
string2 = "123";
if (string1 == string2)
cout << "相等" << endl; // 输出:相等
string 的本质
string
的本质是 C++ 中封装的一个管理字符数组的类- 它封装了动态内存分配、长度管理、字符串操作函数等复杂逻辑
- 因此在现代 C++ 开发中,建议使用
string
来替代字符数组,以提高效率与安全性
32.2 知识点代码
Lesson32_面向对象关联知识点_字符数组和string.cpp
#include <iostream>
using namespace std;
int main()
{
#pragma region 知识回顾 字符数组
//字符数组就是类型为字符char的一维数组
//常用方式:
//方式一:聚合初始化
char charArr[5] = { 'H', 'E', 'L', 'L', 'O' };
char charArr2[] = { 'H', 'E', 'L', 'L', 'O' };
//方式二:单独初始化
char charArr3[5];
charArr3[0] = 'H';
charArr3[1] = 'E';
//这几种声明初始化的方式,如果直接将字符数组拿来打印 会出现问题
//可以直接使用字符串对字符数组进行赋值
char charArr4[] = "Hellow World"; //string
cout << charArr4 << endl;
//原本看起来只有12个字符的字符串 但是长度却有13个
int length = sizeof(charArr4) / sizeof(char);
cout << length << endl;
//通过观察长度,我们发现了一个潜在规则
//对字符数组用字符串去赋值时,会默认在尾部加上一个\0的转移字符
//代表字符串的结束
char charArr5[5];
charArr5[0] = 'A';
charArr5[1] = 'B';
//charArr5[2] = 'X';
//charArr5[3] = 'C';
//charArr5[4] = '\0';
//如果不对字符数组后面的内容进行初始化 并且其中没有\0
//在打印时就不知道何时结束,就会不停的往后读取
//因为没有明确的终止符,程序会根据内存中是否存在 '\0' 停止打印
//可能打印出多余字符,甚至是乱码
//也就是说可能出现访问到字符数组范围之外的内存区域,产生未定义的行为
cout << charArr5[2] << endl;
cout << charArr5 << endl;
//关于“烫”字符
//在内存中,汉字字符使用多字节编码(比如 UTF-8 或 GBK)
//当程序读取到这些内存内容时,会尝试解释它们。
//由于编码规则,有可能形成合法的汉字编码,导致控制台上显示出汉字或其他非预期字符
cout << "****************************" << endl;
#pragma endregion
#pragma region 知识点一 字符数组公共方法
//C++中内置一些关于字符数组的方法
//方便我们对其进行操作
//注意:
// 这些方法其实都是C语言的方法 大家了解即可
//1.strcat_s(字符数组, 字符数组长度, 字符串)
// 作用:将一个字符串连接到另一个字符数组中
// 如果字符数组长度不够会报错
// 操作前:str1 = "123"(长度3),str2 = "456"(长度3),str1的可用空间为7(sizeof(str1)=10)
char str1[10] = "123";
char str2[10] = "456";
strcat_s(str1, sizeof(str1), str2);
cout << str1 << endl; // 输出:123456
//2.strcpy_s(字符数组, 字符数组长度, 字符串)
// 作用:将一个字符串复制到另一个字符数组中
// 如果字符数组长度不够会报错
// 操作前:str1 = "123456"(长度6),目标字符串"7777777"长度7,str1的可用空间为3(sizeof(str1)=10,当前占用6)
strcpy_s(str1, sizeof(str1), "7777777");
cout << str1 << endl; // 输出:7777777
//3.strcmp(字符数组1, 字符数组2)
// 作用:比较两个字符数组是否相同
// 0 代表相同,非0代表不同
// 操作前:str1 = "7777777",比较目标为"7777777"
cout << strcmp(str1, "7777777") << endl; // 输出:0
//4.strlen(字符数组)
// 作用:得到字符数组实际长度(不包含\0)
// 操作前:str1 = "7777777"
cout << strlen(str1) << endl; // 输出:7
#pragma endregion
#pragma region 知识点二 string相关方法
//1.拼接(C++入门中学习过)
// 通过 + 或者 append方法进行拼接
// 操作前:string1 = "123",string2 = "456"
string string1 = "123";
string string2 = "456";
string1.append(string2);
cout << string1 << endl; // 输出:123456
//2.返回字符串长度
// size()/length()
// 操作前:string1 = "123456"
cout << string1.size() << endl; // 输出:6
cout << string1.length() << endl; // 输出:6
//3.判断字符串是否为空
// empty()
// 操作前:string3 = "1"
string string3 = "1";
cout << string3.empty() << endl; // 输出:0(false)
//4.清空字符串
// clear()
// 操作前:string3 = "1"
string3.clear();
cout << string3 << endl; // 输出:(空字符串)
//5.返回容量
// capacity()
// 操作前:string3 = "1234567890123456789"
string3 = "1234567890123456789";
cout << string3.capacity() << endl; // 输出:31(不同环境可能不同)
//6.在指定位置插入字符串
// insert(位置索引, 字符串)
// 注意:不要超出最大位置(包含\0考虑)
// 操作前:string3 = "1234567890123456789"
string3.insert(1, "哈哈");
cout << string3 << endl; // 输出:1哈哈234567890123456789
// 操作前:string3 = "1哈哈234567890123456789"
string3.insert(23, "嘻嘻嘻");
cout << string3 << endl; // 输出:1哈哈234567890123456789嘻嘻嘻
//7.从指定索引位置起删除固定个长度个字符
// erase(位置索引, 长度)
// 注意:不要超出最大位置(包含\0考虑)
// 操作前:string3 = "1哈哈234567890123456789嘻嘻嘻",长度为26
cout << string3.size() << endl; // 输出:26
string3.erase(23, 6); // 修正:原代码中的索引29超出范围
cout << string3 << endl; // 输出:1哈哈234567890123456789
//8.替换指定区间为另一个字符串
// replace(开始位置索引,长度,字符串)
// 操作前:string3 = "1哈哈234567890123456789"
string3.replace(0, 10, "123456");
cout << string3 << endl; // 输出:12345667890123456789
//9.交换两个字符串
// swap(另一个字符串)
// 操作前:string1 = "123456",string2 = "456"
cout << string1 << endl; // 输出:123456
cout << string2 << endl; // 输出:456
string1.swap(string2);
cout << string1 << endl; // 输出:456
cout << string2 << endl; // 输出:123456
//10.删除最后一个字节 需要注意 破坏多个字节字符的问题
// pop_back();
// 操作前:string3 = "12345667890123456789"
string3.push_back('1');
cout << string3 << endl; // 输出:123456678901234567891
// 操作前:string3 = "123456678901234567891"
string3.pop_back();
cout << string3 << endl; // 输出:12345667890123456789
//11.添加单个字符
// push_back(字符)
// 操作前:string3 = "12345667890123456789"
string3.push_back('A');
cout << string3 << endl; // 输出:12345667890123456789A
//12.查找字符串第一次出现的位置 如果找不到返回的是-1 但是一定基础最好用一个数值变量去存储它
// find(字符或字符串)
// 操作前:string4 = "12345627"
string string4 = "12345627";
int i = string4.find("2");
cout << i << endl; // 输出:1
//13.查找最后一次出现的位置(从尾部找) 如果找不到返回的是-1 但是一定基础最好用一个数值变量去存储它
// rfind(字符或字符串)
// 操作前:string4 = "12345627"
i = string4.rfind("2");
cout << i << endl; // 输出:6
//14.查找首次/最后一次 出现传入字符串中 任一字符的位置
// 首次:find_first_of(字符串)
// 最后一次:find_last_of(字符串)
// 操作前:string4 = "12345627"
string4 = "12345627";
i = string4.find_first_of("478");
cout << i << endl; // 输出:3
i = string4.find_last_of("478");
cout << i << endl; // 输出:7
//15.查找第一个/最后一个 不在传入字符串中的字符
// 第一个:find_first_not_of(字符串)
// 最后一个:find_last_not_of(字符串)
// 操作前:string4 = "12345627"
i = string4.find_first_not_of("12367");
cout << i << endl; // 输出:3
i = string4.find_last_not_of("2367");
cout << i << endl; // 输出:4
//16.截取字符串
// substr(起始位置,长度)
// 操作前:string4 = "12345627"
string4 = "12345627";
string string5 = string4.substr(1, 4);
cout << string5 << endl; // 输出:2345
//17.字符串转字符数组
// data()
// 操作前:string4 = "12345627"
const char* charPtr = string4.data();
for (int i = 0; i < string4.size(); i++)
{
cout << charPtr[i] << endl; // 逐行输出:1 2 3 4 5 6 2 7
}
//18.判断字符串内容是否相等
// ==/!=
// 操作前:string1 = "456",string2 = "123456"(经过swap操作后)
string1 = "123";
string2 = "123";
if (string1 == string2)
cout << "相等" << endl; // 输出:相等
#pragma endregion
#pragma region 知识点三 string的本质
//stirng的本质就是一个C++中封装的一个管理字符数组的类
//它封装了动态内存分配、长度管理、字符串操作函数等复杂逻辑
//因此在现代C++开发当中,都建议大家使用string来替代字符数组
//因为这样更高效,安全
#pragma endregion
}
32.3 练习题
写出 string
中提供的截取和替换对应的函数名
C++ 中 std::string
提供了多个用于字符串截取与替换的函数:
substr(pos, len)
:用于从字符串中截取子串,pos
是起始位置,len
是长度;如果省略len
,则从pos
开始截取到末尾。replace(pos, len, str)
:用于从字符串中替换部分内容,从pos
开始替换len
个字符为新的字符串str
。
示例代码如下:
// 操作前:str = "123456789"
string str = "123456789";
// substr(5):从索引5开始截取到末尾
str = str.substr(5);
cout << str << endl; // 输出:6789
// 替换字符串
// 操作前:str = "6789"
// replace(0, 2, "哈哈"):从索引0开始的2个字符替换为"哈哈"
str.replace(0, 2, "哈哈");
cout << str << endl; // 输出:哈哈89
将字符串 "1|2|3|4|5|6|7"
变为 "2|3|4|5|6|7|8"
并输出
目标是抛弃第一个数字(即 1
),并在末尾添加 8
,通过以下步骤实现:
// 操作前:str2 = "1|2|3|4|5|6|7"
string str2 = "1|2|3|4|5|6|7";
// 找到第一个 '|' 的索引,结果为 1
int index = str2.find('|');
// substr(index + 1):从索引2开始截取到末尾,即 "2|3|4|5|6|7"
str2 = str2.substr(index + 1);
cout << str2 << endl; // 输出:2|3|4|5|6|7
// 找到最后一个 '|' 的索引,结果为 8
index = str2.rfind('|');
// substr(index + 1):截取最后一个数字,结果为 "7"
string lastStr = str2.substr(index + 1);
// 将 "7" 转换为整数
int lastNum = stoi(lastStr);
// 让最后一个数字加1,得到8
++lastNum;
// 拼接字符串,追加 |8
str2 += "|" + to_string(lastNum);
cout << str2 << endl; // 输出:2|3|4|5|6|7|8
编写一个函数,将输入的字符串反转(不使用额外空间)
要求是原地修改,即不能开辟新空间用于反转,且不允许使用中间变量交换字符。
例如:输入 hello
,输出为 olleh
。
// 操作前:str3 = 用户输入的字符串
string str3;
cin >> str3;
// 设置两个指针,分别从字符串的两端向中间靠拢
int left = 0;
int right = str3.size() - 1;
while (left < right)
{
// 不使用额外变量交换两个字符
// 使用ASCII码值进行交换,过程如下:
// 第一步:左字符 = 左字符 + 右字符
str3[left] = str3[left] + str3[right];
// 第二步:右字符 = 左字符 - 右字符(即原左字符)
str3[right] = str3[left] - str3[right];
// 第三步:左字符 = 左字符 - 右字符(即原右字符)
str3[left] = str3[left] - str3[right];
++left;
--right;
}
cout << str3 << endl; // 输出:反转后的字符串
说明:
- 本方法使用加减法交换两个变量的值,省去了使用中间变量。
- 这种方式仅适用于基本数据类型(如
char
),且在字符值不溢出时安全。 - 优点是空间复杂度为
O(1)
,无需额外内存。
32.4 练习题代码
Lesson32_练习题.cpp
#include <iostream>
#include <string>
using namespace std;
int main()
{
#pragma region 练习题一
// 请写出string中提供的截取和替换对应的函数名
// 截取字符串
// 操作前:str = "123456789"
string str = "123456789";
// substr(5) 从索引5开始截取到末尾
str = str.substr(5);
cout << str << endl; // 输出:6789
// 替换字符串
// 操作前:str = "6789"
// replace(0, 2, "哈哈") 从索引0开始的2个字符替换为"哈哈"
str.replace(0, 2, "哈哈");
cout << str << endl; // 输出:哈哈89
#pragma endregion
#pragma region 练习题二
/*请将字符串 1|2|3|4|5|6|7
变为 2|3|4|5|6|7|8
并输出*/
// 1.截取后面的内容,相当于抛弃掉1|
// 操作前:str2 = "1|2|3|4|5|6|7"
string str2 = "1|2|3|4|5|6|7";
int index = str2.find('|'); // 找到第一个'|'的索引,结果为1
// substr(index + 1) 从索引2开始截取到末尾
str2 = str2.substr(index + 1);
cout << str2 << endl; // 输出:2|3|4|5|6|7
// 2.在最后一个数字的基础上去加上一个 n + 1 ,并且前面有一个 |
// 操作前:str2 = "2|3|4|5|6|7"
index = str2.rfind('|'); // 找到最后一个'|'的索引,结果为8
// substr(index + 1) 截取最后一个数字
string lastStr = str2.substr(index + 1); // lastStr = "7"
int lastNum = stoi(lastStr); // 转换为整数7
++lastNum; // 加1后变为8
// 拼接字符串
str2 += "|" + to_string(lastNum);
cout << str2 << endl; // 输出:2|3|4|5|6|7|8
#pragma endregion
#pragma region 练习题三
/*编写一个函数,将输入的字符串反转。
不要使用中间商,你必须原地修改输入数组。交换过程中不使用额外空间
比如:输入{ ‘h’,‘e’,‘l’,‘l’,‘o’ }
输出{ ‘o’,‘l’,‘l’,‘e’,‘h’ }*/
// 操作前:str3 = 用户输入的字符串
string str3;
cin >> str3;
int left = 0;
int right = str3.size() - 1;
while (left < right)
{
// 不使用额外变量交换两个字符
// 得到left和right ASCII码的总和 left + right
str3[left] = str3[left] + str3[right];
// left + right - right = left
str3[right] = str3[left] - str3[right];
// left + right - left = right
str3[left] = str3[left] - str3[right];
++left;
--right;
}
cout << str3 << endl; // 输出:反转后的字符串
#pragma endregion
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com