C++ 中数组与字符串
目录
一、数组的特征
- 数组是存放类型相同的对象的容器,这些对象没有名称,只能根据其所在的位置来进行访问。
- 数组的大小是确定不变的,不能随意增加删除元素。
- 数组中的元素在内存中是连续的。
- 数组会最终会退化成指针,指针的地址即为数组的首元素地址。
- 数组的性能会优于vector, 但操作灵活性会有所损失。
- 字符类型的数组在表示C类型的字符串时,其结尾必须要有
\0
作为结束符。
二、 一般数组声明与定义
1、 栈上的数组(stack)
- 数组在编译的时候,其维度(即元素的个数)必须是已知的。所以其维度必须是常量或常量表达式。
- 由于数组会隐式的退化成指向首元素的指针(即数组名),所以不能用数组的内容来初始化或者直接赋值给其它数组
const char* arr01 = "Test"; // 初始化一个字符串,将其首地址赋给指针变量 arr01
char arr02[] = "Test"; // 初始化一个字符数组,可以进行修改数组元素的内容
int arr11[4]; //声明一个长度为10的整型数组
int arr12[4] = { 1,2,3,4}; //初始化一个数组, 右边元素个数不能超过4个
int arr13[] = { 1,2,3,4,5 }; //初始化数组,根据初始化的元素来推断元素的个数。
//为数组进行赋值:由于数组会隐式的退化成指针 只能对每个元素进行赋值
arr11[0] = 1;
arr11[1] = 1;
arr11[2] = 1;
arr11[3] = 1;
arr11 = arr12; // 错误: 不能把一个数组直接赋值给另一个数组。
int arr14[] = arr12; // 错误: 不能用一个数组初始化另一个数组。
int *arr15 = arr12; // 正确: 定义一个指针来指向arr12数组,arr12代表一个指针
int num1 = 10;
constexpr int num2 = 10;
int arr16[num1]; //错误:num1 不是常量表达式
int arr17[num2]; //正确:num2 为常量表达式
2、堆上的数组(heap) —— 动态数组
- new 会返回指向该数组首元素的指针,也是该数组的指针地址
- 动态数组元素的个数可以不是常量表达式
- new 的动态数组需要释放,否则会造成内存泄漏的问题
int num = 4;
int* arr21 = new int[num]; // 正确: 动态数组不需要 num 为常量表达式,且 num 可以为 0.
int* arr22 = new int[4]; //new 一个长度为4的整型数组,未进行初始化。
int* arr23 = new int[4](); //new 一个长度为4的整型数组, 并将其所有值按默认值进行初始化, 整型数组默认值为0
int* arr24 = new int[4]{ 1,2,3,4 }; // 正确: 初始化元素个数必须小于等于指定要 new 的元素个数(在此即为4个元素)
动态数组的释放:销毁 new 的动态数组中的元素,并释放所分配的内存空间。数组中的元素按逆序销毁,即最后一个元素先被销毁,然后是倒数第二个,依次来销毁所有的元素。
// arr 必须指向一个动态分配的数组或为空
delete[] arr
【注】new 单一元素与数组的区别:
int *p1 = new int(10); // 在堆上初始化一个int类型的元素,其值为10,而不是创建一个数组。
int *p2 = new int[10]; // 在堆上创建一个int类型的数组,包含10个元素。
delete p1; // 释放new的元素
delete[] p2; // 释放new的数组
三、字符串的三种表示方式:
1、 std::string
的形式,使用STL的 string class,方便对字符串进行各种处理,提供多种API:
std::string str2 = "Hello test 02";
size_t count = str2.size();
2、 const char*
常量指针的形式,此时常量指针的内容不能进行修改:
// C++中必须为常量指针,C 语言可以无需const
const char* str1 = "Hello test";
3、 字符数组的形式,将字符串以数组的形式进行表示:
// 如果指定字符数组的长度,则字符数组的长度值 >= 字符的个数 + 1,即字符的个数加上结束空字符'\0'
char str3[20] = "123456";
// 可以省略字符数组的长度,其默认长度等于:字符的个数加上结束空字符'\0'
char str4[] = "123456";
// 计算字符数组的长度 (注:包含末尾的空结束字符)
int arrCount = sizeof(str4) / sizeof(str4[0]);
【注】如果是作为.dll/.so的形式来对外提供自己的库,推荐使用字符数组的形式; 如果是只是自己项目内部函数使用,推荐使用std::string
四、字符数组来表示字符串
1、C 风格字符串
由于 C 语言并没有字符串,而是使用以空字符\0
为终止符的字符数组来表示字符串,即常说的C-Style字符串,一般利用指针来操作这些字符串。其表现形式主要有两种:
- 以字符指针的形式来表示:
// p001 表示指向字符数组的指针,其数组空间大小是实际字符长度加1,以末尾的`\0`来表示字符结束。
// 该方式指向的字串不能进行修改编辑
const char* p001 = "Test"
- 以字符数组的形式来表示,该方式创建的字串可以进行修改编辑:
//p002所占空间长度为5,包括默认自动添加的'\0'结束符
char p002[] = "Test";
//指定的字符数 >=(初始化字符串中的字符个数 + 1)
char p003[10]="Test";
//p004 需要在末尾添加`\0`作为最后一个元素,否则在遇到处理字符串的时候,将无法识别到字符结束的标志
char p004[] = { 'T','e','s','t','\0' };
2、C 风格字串处理
在C++标准库之外,经常需要处理C风格字符串,为此C++在cstring
头文件中定义了很多处理C-Style字符串的函数(cstring
是C中的string.h
的C++版本)。
常用处理C风格字符串函数如下:
//1. 计算字符串长度
strlen(pChStr); //返回单字节字符串长度,空结束字符`\0`不计算
wcslen(pWchSrc); //返回宽字符字串长度,不包括结束符`\0`
//2. 复制字串,或将内容写入字串
strcpy_s(pChDest, SizeNum, pChSrc); //单字节字串
sprintf_s(pChDest, SizeNum, pChSrc); //单字节字串
wcscpy_s(pWchDest, SizeNum, pWchSrc); //宽字符字串
swprintf_s(pWchDest, SizeNum, pWchSrc); //宽字符字串
//3. 比较字串是否相等
strcmp(p1, p2); //单字节字串:相等返回0;p1>p2 返回正值;p1<p2返回负值
wcscmp(p1, p2); //宽字符字符:相等返回0
//4. 字串连接
//单字节字串:将pSrc字串添加到 pDest 后面,以`\0`结束,返回拼接后的pDest字串。当pDest空间不足时,将会丢弃pSrc的部分元素
strcat(pDest, pSrc);
//单字节字串:需要指定合并后字符的总个数(包含终止符`\0`),来保证空间充足
strcat_s(pDest,count, pSrc);
//多字节字符:需要指定合并后字符的总个数(包含终止符`\0`),来保证空间充足
wcscat_s(pDest,count, pSrc);
- 由于不能直接将字符数组用来初始化或者赋值给另一个字符数组,所以经常需要进行字符串拷贝写入处理
const char* pChSrc = "Test";
const wchar_t* pWchSrc = L"Test";
char pChDest[10];
wchar_t pWchDest[10];
//单字节: 将 pChSrc的字符串拷贝到 pChDest中
strcpy_s(pChDest, 5, pChSrc);
//宽字符: 将pWchSrc 字串拷贝到pWchDest中的两种方式:
wcscpy_s(pWchDest, 5, pWchSrc); // 方式1
swprintf_s(pWchDest, 5, pWchSrc); // 方式2
五、字符串的格式化
将字符串格式成指定的形式,常用的方法:
int sprintf(char *str, const char *format, ...)
:如果buffer区不足将会导致溢出的问题。int sprintf_s( char* restrict buffer, rsize_t bufsz, const char* restrict format, ... );
:该方式会检查buffer的大小,避免溢出,超出时会自动截断,是安全的用法。返回值在不溢出的情况下是写入字串实际大小,在溢出时是写入所有字串所期望的大小。int snprintf( char* restrict buffer, size_t bufsz, const char* restrict format, ... );
:该方式同样会检查buffer的大小避免溢出问题。返回值在不溢出的情况下是写入字串实际大小,在溢出时是写入所有字串所期望的大小。
char buffA[1024] = {0};
sprintf(buffA, "%s, %d", "test", 10);
sprintf_s(buffA, sizeof(buffA), "%s, %d", "test", 11);
snprintf(buffA, sizeof(buffA), "%s, %d", "test", 12);
参考资料:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!