从C到C++:数组和字符串的“解放宣言“
·
学数组和字符串这一章,我最大的感受是:终于不用再跟char数组死磕了!
C语言里,字符串就是char数组,各种越界、内存问题、strcpy/strcat/strlen…写起来费劲还容易出bug。到了C++,有了string类和vector容器,写代码突然就舒服了。
这篇就聊聊从C转C++时,数组和字符串这块的"幸福感提升"。
一、老熟人:C风格的数组和字符串
先快速过一遍C里就有的东西,C++基本都保留了:
- 一维数组、二维数组
int arr[10]; // 一维数组
int matrix[3][4]; // 二维数组
定义、初始化、访问元素,和C一模一样。 - C风格字符串
char str[] = “hello”; // 字符数组
char *p = “world”; // 字符串常量指针
还有那些熟悉的字符串函数:strlen、strcpy、strcat、strcmp、sprintf…
回忆一下:刚学C的时候,谁没写过越界的字符串?谁没用strcpy写出过缓冲区溢出?C风格字符串就是这么"锻炼人"。
二、C++的大杀器:string类
如果说C++只能选一个我最喜欢的特性,string绝对能排进前三。 - 再也不用记一堆字符串函数了
C风格字符串操作:
#include
char s1[100] = “hello”;
char s2[100] = “world”;
// 拼接
strcat(s1, " ");
strcat(s1, s2); // 还要担心缓冲区够不够大
// 比较
if (strcmp(s1, s2) == 0) { … } // 等于0才是相等,反直觉
// 复制
strcpy(s1, s2); // 还是要担心缓冲区
C++ string操作:
#include
using namespace std;
string s1 = “hello”;
string s2 = “world”;
// 拼接,直接+
string s = s1 + " " + s2; // 不用担心溢出,自动管理内存
// 比较,直接==
if (s1 == s2) { … } // 直观!
if (s1 > s2) { … } // 大小比较也自然
// 赋值,直接=
s1 = s2; // 简单直接
对比一下,体验差太多了! - string的常用操作
表格
操作 用法 说明
获取长度 s.size() 或 s.length() 返回字符个数
判断空 s.empty() 空返回true
清空 s.clear() 清空内容
追加 s += “abc” 或 s.append(“abc”) 在末尾追加
插入 s.insert(pos, “abc”) 在pos位置插入
删除 s.erase(pos, len) 删除从pos开始的len个字符
取子串 s.substr(pos, len) 取子字符串
查找 s.find(“abc”) 查找子串,返回位置
替换 s.replace(pos, len, “abc”) 替换
还有很多方法,用的时候查文档就行。 - string和C风格字符串的转换
有时候需要用C风格的字符串(比如调用老的C函数),string提供了c_str()方法:
string s = “hello”;
const char p = s.c_str(); // 得到const char指针
// 反过来也可以
string s2 = p; // char*直接转string
注意:c_str() 返回的指针是 const 的,不要去修改它指向的内容。而且这个指针可能会在string被修改后失效,别存着一直用。 - string的"坑"
虽然string很好用,但也有一些需要注意的地方:
坑1:用[]访问越界不会检查
string s = “hello”;
s[10] = ‘a’; // 越界了!不会报错,但行为未定义
想用安全的访问,用 s.at(10),越界会抛异常。
坑2:字符串字面量不是string
“hello” + “world”; // 错误!两个char不能相加
因为"hello"是C风格字符串(const char),不是string对象,不能直接+。想拼接得转成string:
string(“hello”) + “world”; // 可以
三、从C到C++的思维转变 - 从"手动管理"到"自动管理"
C里数组和字符串的内存都要自己管,C++里string和vector帮你管了。不用再担心缓冲区溢出、内存泄漏这些问题。 - 从"字符数组"到"字符串对象"
C里字符串就是个特殊的char数组,C++里string是个完整的对象,有自己的方法和行为。写代码的思路从"操作内存"变成了"操作对象"。 - 从"数组=指针"到"数组=容器"
C里数组和指针关系暧昧,很容易搞混。C++里vector和string都是独立的容器对象,有自己的接口,不用和指针纠缠。
四、我的踩坑记录
坑1:string的[]不检查越界
前面说过了,用[]访问越界是未定义行为,不会报错。要安全访问用at()。
坑2:C风格字符串和string混用
string s = “hello”;
if (s == “world”) { … } // 没问题,"world"会自动转string
if (“hello” == “world”) { … } // 有问题!这是在比较两个const char*指针,不是比较内容
两个C风格字符串比较要用strcmp,不能直接用==。
四、一些实用建议 - 尽量用string,少用char数组
除非有特殊理由(比如性能极致优化、和C库交互),否则优先用string。安全、方便、功能强。 - 范围for遍历真香
能用范围for就别写下标,简洁又不容易写错。
写在最后
数组和字符串这一章,给我的感觉是:C++终于把C里最让人头疼的部分给包好了。
C的字符串和动态数组,不是不能用,而是用起来太"糙"了——啥都要自己来,稍不注意就出问题。C++的string和vector把这些底层细节都藏起来了,让你能专注于逻辑本身,而不是跟内存较劲。
当然,这不是说C风格的数组和字符串就不用学了——很多老代码、C库还是要用的。但平时写C++代码的时候,能用上string和vector就尽量用,效率和安全性都高很多。
更多推荐
所有评论(0)