跳转至

一维字符数组

字符串可以用一维字符数组表示,也可以用 string 表示。

前者是 C 风格的字符串,后者是 C++ 风格的字符串。

一维字符数组

定义

char s[110]; 

初始化

char s[110] = {'z', 'q'};
char s[110] = "zq";

这两种初始化的方法,存储到字符数组中的格式是完全一致的。

下面是数组中的存储内容

s[0] = 'z'
s[1] = 'q'
s[2] = '\0'

字符数组存入相应的字符后,自动在末尾添加一个特殊字符 '\0',作为字符串的结束标记。

'\0' 对应的 ASCII 码为 0。

输入输出

使用 cin, cout

char s[110];

int main() {
    cin >> s;
    cout << s;

    return 0;
}

使用 scanf(), printf()

char s[110];

int main() {
    scanf("%s", s);
    printf("%s", s);

    return 0;
}

访问

s[0] 访问第0位字符
s[i] 访问第i位字符

遍历

for (int i = 0, len = strlen(s); i < len; i++) 
    cout << s[i];

基础操作

int len = strlen(s); // 获取字符串的长度

int p = strcmp(s1, s2); // 判断 s1, s2 是否相等。相等是 0,小于是负数,大于是正数

strcat(s1, s2); // s1 后面拼接上 s2

strcpy(s1, s2); // s2 复制给 s1,s1 存的东西变成和 s2 一样

memcpy(s1, s2, sizeof s1); // 把 s2 的值赋值给 s1

关于以 '\0' 结尾的讨论

从下面两个计算机实验中,我们可以得到这样的结论:

\0 不占字符串的长度,但占用字符串的存储空间。

image-20250912154541600

image-20250912154629178

string

在标准模板库 STL 中,建立了有关字符串操作的 string 类。

定义

string s;

初始化

string s; // 默认是空串,即"", 一个双引号,中间什么都没有,空串
string s = "zq";

输入输出

int main() {
    string s;
    cin >> s;

    cout << s;

    return 0;
}

访问

s[0] 访问第0位字符
s[i] 访问第i位字符

遍历

for (int i = 0, len = s.size(); i < len; i++) 
    cout << s[i];
for (auto c : s) cout << c;

// 这是C++11的写法,auto 表示自动识别变量类型

基础操作

s1 = s;           // 复制操作

s += "def";       // 拼接字符串
s += 'g';         // 拼接字符

if (s == "zq")    // 判断是否相等
if (s < "ab")     // 按字典序比大小关系

// 截取子串
cout << s.substr(1, 2);  // 从下标为1那个位置,截取长度为2的子串
cout << s.substr(1);     // 从下标为1那个位置,截取右边的所有内容

// 插入子串
s.insert(1, "xxx");      // 在下标为1那个位置,插入一个字符串"xxx" 

// 替换子串
s.replace(1, 2, "xxx");  // 将从下标1开始,长度为2的子串,替换为"xxx"

// 查找子串、查找字符,返回第一次出现的位置,不存在返回 string::npos(一般理解为-1)
// 常用于判断一个字符串是否为另一个字符串的子串
s.find("zq");    // 查找子串zq第一次出现的位置
s.find('q');     // 查找字符q第一次出现的位置
if (s.find("zq") == string::npos) cout << "Not find"; // 如果没找到

s.find("zq", p); // 从下标p那个位置往后找"zq"第一次出现的位置

// 这个操作通常用来向右,找到一个替换一个,循环迭代向右替换
// 直到都替换完了,结束
string s = "zqoizqoizqoizqoizqoizqoizqoi";
int p = 0;
while (s.find("zq", p) != string::npos) {
    p = s.find("zq", p);
    s.replace(p, 2, "NB");
}
cout << s;

// 翻转字符串
reverse(s.begin(), s.end());

string 的长度和占用存储空间的问题

从下面三个实例中,我们可以得到这样的结论:

.size() 表示字符串的长度,sizeof 表示占用存储空间都是 32 字节。

image-202509121606161 23

image-20250912160637175

image-20250912160755894

统计字符

一个由大小写字母、数字组成的字符串,

统计26个大写字母、26个小写字母、10个数字字符出现的次数

int cntA[30], cnta[30], cnt[15];

int main() {
    string s;
    cin >> s;
    for (auto c : s) {
        if (c >= 'A' && c <= 'Z') cntA[c - 'A']++;
        if (c >= 'a' && c <= 'z') cnta[c - 'a']++;
        if (c >= '0' && c <= '9') cnt[c - '0']++;
    }
}

大小写转换

输入一个字符串,全部转换为小写字母

for (int i = 0, len = s.size(); i < len; i++)
    if (s[i] >= 'A' && s[i] <= 'Z') s[i] += 32;

cout << s;
// 也可以这样写
for (auto &c : s) 
    if (c >= 'A' && c <= 'Z') c += 32;

cout << s;

统计字符串

前文对字符进行了统计,可以用字符进行存储,原理是用字符 ASCII 码相对距离作为数组的下标,存储起来。

对于字符串,那怎么表示呢?

在这里,我们需要使用到标准模板库 STL 当中的 map

int main() {
    int n;
    string s;
    map<string, int> mp;

    while (n--) {
        cin >> s;
        mp[s]++:
    }

    for (auto i : mp) cout << i.first << ' ' << i.second << endl; // 输出每个字符串出现了几次

    return 0;
}

读入一整行

使用 getline()

cin 读入到空格、换行、EOF(文件终止符) 的时候,会终止读入。

如果我们想把一整行,把空格字符当成字符串的一部分读入,使用 getline()

string s;
getline(cin, s);

getline()会读入一整行,但当我们不需要读入空格时候,我们正常使用 cin

注意,不要滥用 getline()

过滤空格

我们通过 getline() 读入一整行,把其中的空格过滤掉。

string s;
getline(cin, s);

for (auto c : s)
    if (c != ' ') cout << c;
// 把过滤之后的字符,存起来
string s, s2;
getline(cin, s);

for (auto c : s)
    if (c != ' ') s2 += c;

cout << s2;