C++数组与字符串:从基础到实战技巧
C++中的数组和字符串是处理数据集合和文本的基础工具。数组用于存储相同类型的元素集合,而字符串则专门用于处理文本数据。C++提供了两种主要的字符串处理方式:C风格字符串(字符数组)和C++的std::string
类。
📊 1. 数组 (Arrays)
数组是相同类型元素的集合,这些元素在内存中连续存储。数组的大小在定义时确定,且不能改变。
一维数组
-
声明与初始化。
数组的声明需要指定元素类型、数组名和大小。初始化可以在声明时进行。
int numbers[5];// 声明一个包含5个整数的数组,未初始化int numbers[5] = {1, 2, 3, 4, 5};// 声明并初始化int numbers[] = {1, 2, 3, 4, 5};// 编译器自动计算大小
如果初始化值少于数组元素,剩余元素会自动初始化为0(对于基本数据类型)
-
访问元素
通过索引访问数组元素,索引从0开始。
int first = numbers[0];// 访问第一个元素 numbers[4] = 10;// 修改第五个元素
-
特点
- 内存连续,访问高效。
- 大小固定,无法动态扩容。
- 需注意数组越界访问,这可能引发未定义行为。
多维数组
多维数组,如二维数组,可视为“数组的数组”,常用于表示矩阵或表格。
-
声明与初始化
int matrix[2][3] = {{1, 2, 3}, {4, 5, 6}};// 2行3列int matrix[2][3] = {1, 2, 3, 4, 5, 6};// 按顺序初始化
-
访问元素
使用多个索引访问元素。
int value = matrix[1][2];// 访问第二行第三列(值为6)
动态数组
使用new
和delete[]
在堆上动态分配和释放内存。
int size = 5;
int* dynamicArray = new int[size];// 动态分配// 使用 dynamicArray...delete[] dynamicArray;// 释放内存
动态数组需手动管理内存,防止内存泄漏。
🔤 2. 字符串 (Strings)
C++中有两种主要的字符串表示方式:C风格字符串和std::string
类。
C风格字符串 (C-Style Strings)
C风格字符串本质是以空字符'\0'
结尾的字符数组
。
-
声明与初始化。
char str1[] = "Hello";// 编译器自动添加'\0',数组长度为6char str2[6] = {'H', 'e', 'l', 'l', 'o', '\0'};// 手动添加终止符
字符串字面量用双引号括起,编译器会自动在其末尾添加空字符
-
常用函数。
使用C标准库函数(需包含
<cstring>
)进行操作:#include <cstring>char str1[20] = "Hello"; char str2[] = "World";strlen(str1);// 获取字符串长度(不包括'\0')strcpy(str1, str2);// 复制字符串(需确保目标空间足够)strcat(str1, "!");// 连接字符串(需确保目标空间足够)strcmp(str1, "Hello World!");// 比较字符串(相等返回0)
注意:使用
strcpy
、strcat
等函数时,必须确保目标字符数组有足够的空间,否则可能导致缓冲区溢出
std::string类
C++标准库提供的std::string
类(需包含<string>
头文件)封装了字符串操作,自动管理内存,更安全便捷
。
-
声明与初始化
#include <string> std::string s1;// 空字符串 std::string s2 = "Hello, World!";// 初始化std::string s3(s2);// 拷贝构造
-
常用操作
std::string
支持丰富的操作:s1 = "Hello"; s2 = "World"; std::string s4 = s1 + ", " + s2;// 字符串拼接(使用+运算符) s1.append(" World!");// 追加字符串int len = s1.length();// 或 s1.size(),获取字符串长度char ch = s1[0];// 通过索引访问字符(不检查边界) ch = s1.at(0);// 使用at()访问(会检查边界,越界抛出异常)std::string sub = s1.substr(7, 5);// 提取子串(从位置7开始,长度为5)size_t pos = s1.find("World");// 查找子串,返回首次出现的位置(未找到返回std::string::npos) s1.replace(7, 5, "C++");// 替换子串(从位置7开始,替换5个字符为"C++") s1.insert(7, "Beautiful ");// 插入字符串 s1.erase(7, 10);// 删除子串(从位置7开始,删除10个字符)if (s1 == s2) {/* 比较字符串 */ }// 支持关系运算符比较
-
输入输出。
使用
getline
读取整行文本(包括空格):std::string name; std::cout << "Enter your full name: "; std::getline(std::cin, name);// 读取整行 std::cout << "Hello, " << name << std::endl;
使用
cin
进行输入时,遇到空格、制表符或换行符会停止读取
转换
-
std::string
与 C风格字符串互转。std::string s = "Hello"; const char* cstr1 = s.c_str();// 转换为C风格字符串(只读,指向s的内部数据)const char* cstr2 = s.data();// C++17前与c_str()类似,C++17起可能不以空字符结尾char arr[20]; std::strcpy(arr, s.c_str());// 将s的内容复制到可修改的字符数组arr中const char* cstr = "World"; std::string s_from_c = cstr;// C风格字符串转换为std::string
注意:
c_str()
返回的指针在std::string
对象发生修改后可能失效
⚖️ 3. 对比与选择
特性 | C风格字符串 | std::string |
---|---|---|
内存管理 | 手动管理,易出错 | 自动管理,避免泄漏 |
安全性 | 易缓冲区溢出/越界 | 更安全,边界检查 |
功能 | 基础函数(strlen, strcpy等) | 丰富方法(拼接、查找、替换等) |
性能 | 开销小,适合底层或嵌入式 | 动态扩容可能带来开销,但通常更便捷 |
建议:在现代C++开发中,优先使用std::string
,除非在与C代码交互或对性能有极端要求的场景下才考虑使用C风格字符串
。
💡 4. 注意事项
- 数组越界:访问数组时,确保索引在
[0, size-1]
范围内,越界访问会导致未定义行为。 - 字符串结束符:操作C风格字符串时,务必确保其以
'\0'
结尾,否则相关字符串函数可能无法正常工作甚至导致程序崩溃。 - 空间充足:对C风格字符串进行拼接、复制等操作前,务必确认目标字符数组有足够的空间,防止缓冲区溢出。
std::string
的c_str()
:不要存储c_str()
返回的指针并在后续修改std::string
对象,除非已重新获取。该指针指向的数据可能在std::string
修改后失效。
掌握数组和字符串的基础知识是进行有效C++开发的关键。根据具体场景选择合适的工具,并始终牢记安全操作的准则。