字符串

字符串变量与常量

字符串变量

  • 字符串是一个特殊的字符数组,以空字符\0结尾
  • 空字符\0自动添加到字符串的内部表示中
  • 在声明字符串变量的时候,要时刻记得为这个空结束符预留一个额外元素的空间:char str[11] = {"helloworld"},十个字符要留11个位置

字符串常量

  • 字符串常量就是一对双引号括起来的字符序列:"helloworld"
  • 字符串常量中的每个元素可以作为一个数组元素访问
  • 字符串常量也是以'\0'结尾的

字符串的指针表示

1
const char* pStrHelloWorld = "helloworld";

表示一个char型的指针变量,指向内存中一个存储字符串“helloworld”的地址。

定义字符串的两种方式,char[]和char*,要区分以下两个概念:

  • 区分地址本身和地址存储的信息;
  • 区分可变与不可变;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int main()
{
char strHello[11] = { "helloworld" };
//strHello是数组变量,它本身的值是不允许改变的,但是它指向的区域的值strHello[index]是可以改变的
strHello[2] = '6'; //strHello = he6loworld
//strHello = { "helloworld" }; //不允许改变了,编译不通过


//ptrHello是指针变量,它本身是可以改变的,但是ptrHello[index]指向的值可变与否要取绝与所指向的区间是否可以改变
const char* ptrHello_1 = "helloworld"; //指针指向常量区(必须要加const),ptrHello[index]不可改变,但本身指向的地址可以变。
ptrHello_1 = "change";

char tmp[7] = "change";
char* ptrHello_2 = strHello; //指针指向数组变量,ptrHello[index]可以改变,本身也可以变
ptrHello_2[2] = 'l';
ptrHello_2 = tmp;

return 0;
}

字符串操作

头文件:string.h

字符串长度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
strlen(s);    //返回字符串s的长度,要注意字符串的长度不包含'\0'。

sizeof(s); //返回字符串所占用的空间,包含'\0'


int main()
{
char strA[11] = "helloworld";
auto n1 = sizeof(strA); //11
auto n2 = strlen(strA); //10


wchar_t strB[11] = L"helloworld";
auto n3 = sizeof(strB); //22
auto n4 = wcslen(strB); //10

return 0;
}

字符串比较

1
2
3
4
5
strcmp(s1,s2); 
wcscmp(s1,s2);
//s1 == s2,返回0
//s1 < s2 ,返回值小于0
//s1 > s2 ,返回值大于0

两个字符串自左向右逐个字符相比,按照ASCII值大小来比较,直到出现不同字符或遇到'\0'为止

字符串拷贝

1
2
3
strcpy(s1,s2);   //赋值字符串s2到字符串s1

strncpy(s1,s2,n); //将字符串s2中的前n个字符拷贝到s1中

要注意一个陷阱,一定要保证字符串s1的内存大小能存的下要拷贝的s2的大小

字符串拼接

1
strcat(s1,s2);   //将字符串s2拼接到s1后面

这个更加要注意,s1的大小要足够存放拼接后的s1+s2字符串的大小 两个字符串指针不能直接相加,拼接必须要用这个函数。(指针相加是什么操作啊(#`O′))

字符串查找

1
2
strchr(s1,ch);   //指向字符串s1中字符ch第一次出现的位置
strstr(s1,s2); //指向字符串s1中字符串s2的第一次出现的位置

安全函数

以上程序都需要我们进行边界检查以防止内存问题。现在我们往往在程序中使用更加安全的API函数

上述所有API函数都有其_s版本,如strcpy_s(),在执行操作的同时要告诉系统当前可使用的缓冲区的大小。 strlen()的安全版本是strnlen_s(),传入字符串的同时要传入一个最大的边界,以防止某些字符串没有\0结束标志 。

字符串操作重点

  1. C原始字符串的操作在安全性和效率中存在一定问题: 1. 一定要注意不要缓冲区溢出。 2. strlen的效率可以提升,当字符串很长的时候strlen的效率不高,我们可以用空间换时间,在定义字符串的时候用变量记住它的长度,不使用strlen函数来计算
  2. 目前有一个很好的开源库Redis字符串:Redis库

string类

C++标准库中提供了string类型专门表示字符串

1
2
#include<string>
using namespace std;

使用string可以更加方便和安全的管理字符串,对性能要求不是特别高的场景可以使用。

定义

1
2
3
4
string s;   //定义空字符串
string s = "helloworld"; //定义并初始化
string s("helloworld");
string s = string("helloworld");

字符串长度

1
2
3
cout<<s1.length()<<endl;    //输出字符串长度
cout<<s1.size()<<endl; //本质和上面一样
cout<<s1.capacity()<<endl; // 字符串的容量

字符串比较

直接使用== != < > >= < = 即可,比较ASCII码来比较。

转换为C风格字符串

1
2
string s1 = "hello";
const char* c_str1 = s1.c_str();

随机访问

字符串本身可以使用下标的方式访问

1
2
string s = "hello";
cout<<s[0]<<endl;

字符串拷贝

不需要使用函数,直接使用=赋值

1
2
string s1 = "hello";
string s2 = s1;

字符串拼接

string重载了+和+=,不需要使用函数

1
2
3
string s1 = "hell0",s2 = "world";
string s3 = s1+s2;
s1 += s2;