20260227 120039 Cpp 入门第六课

20260227_120039_CPP_入门第六课.md

第六章:处理文字——字符串

你好!欢迎来到第六章!在前面的章节,我们学习了数字和数组。但生活中我们更多接触的是文字,比如名字、句子、文章。在C++中,文字数据叫做字符串。这一章我们会学习如何存储和操作字符串,包括古老的C风格字符串和更方便的C++ string 类。学完本章,你就能编写处理文字的程序了!


6.1 字符串程序范例

我们先来看一个简单的程序,它使用了C++中的 string 类型(最方便的一种字符串)。

#include <iostream>
#include <string>   // 使用string需要包含这个头文件
using namespace std;

int main() {
    string name;    // 定义一个字符串变量,名字叫name

    cout << "请输入你的名字:";
    cin >> name;    // 输入字符串(注意:不能有空格)

    cout << "你好," << name << "!欢迎学习C++字符串!" << endl;

    return 0;
}

运行示例(假设输入“小明”):

请输入你的名字:小明
你好,小明!欢迎学习C++字符串!

这个程序展示了字符串的基本输入输出。接下来我们会深入学习字符串的各种用法。


6.2 字符串的用法

6.2.1 字符的操作

字符串是由一个个字符组成的。在C++中,字符用 char 类型表示。我们先学会操作单个字符。

字符的定义和赋值
char ch1 = 'A';      // 单个字符用单引号括起来
char ch2 = 'b';
char ch3 = '5';
char ch4 = '!';
字符的输入输出
char ch;
cout << "请输入一个字符:";
cin >> ch;           // 输入一个字符
cout << "你输入的字符是:" << ch << endl;
字符的ASCII码

每个字符在计算机中都有一个对应的整数编码,叫做ASCII码。例如 'A' 的ASCII码是65,'a' 是97,'0' 是48。字符可以和整数进行运算。

char ch = 'A';
cout << (int)ch << endl;   // 输出65,将字符转为整数
cout << char(65) << endl;  // 输出A,将整数转为字符
字符的运算

因为字符本质上是整数,所以可以进行加减运算。

char ch = 'A';
ch = ch + 1;                // 变成 'B'
cout << ch << endl;

// 小写转大写
char lower = 'b';
char upper = lower - 32;    // 因为小写字母比大写字母ASCII码大32
cout << upper << endl;      // 输出'B'
常用字符判断(需要包含 <cctype> 头文件)

C++提供了许多判断字符类型的函数,非常方便。

函数 作用
isalpha(ch) 判断是否是字母
isdigit(ch) 判断是否是数字
islower(ch) 判断是否是小写字母
isupper(ch) 判断是否是大写字母
isspace(ch) 判断是否是空格
tolower(ch) 转换为小写
toupper(ch) 转换为大写
#include <iostream>
#include <cctype>   // 字符处理函数
using namespace std;

int main() {
    char ch;
    cout << "请输入一个字符:";
    cin >> ch;

    if (isalpha(ch)) {
        cout << ch << " 是字母" << endl;
        if (islower(ch)) {
            cout << "它是小写字母,大写形式是:" << char(toupper(ch)) << endl;
        } else {
            cout << "它是大写字母,小写形式是:" << char(tolower(ch)) << endl;
        }
    } else if (isdigit(ch)) {
        cout << ch << " 是数字" << endl;
    } else {
        cout << ch << " 是其他字符" << endl;
    }

    return 0;
}

6.2.2 字符数组

字符数组是C语言风格的字符串,就是用一个数组来存放多个字符,最后以 '\0' 结尾。

定义和初始化
char str1[10] = {'H', 'e', 'l', 'l', 'o', '\0'};  // 手动加结束符
char str2[10] = "Hello";        // 自动在末尾加 '\0',最常用
char str3[] = "Hello";          // 编译器自动计算大小为6(包括'\0')
访问和遍历
char str[] = "Hello";
for (int i = 0; i < 5; i++) {
    cout << str[i] << " ";      // 输出 H e l l o
}
cout << endl;

// 也可以用while循环,直到遇到'\0'
int i = 0;
while (str[i] != '\0') {
    cout << str[i];
    i++;
}
修改字符数组中的元素
char str[] = "Hello";
str[0] = 'h';   // 修改第一个字符
cout << str;    // 输出 "hello"

注意:字符数组的大小一旦定义就不能改变,所以要保证足够大。

6.2.3 字符串的输入和输出

C风格字符串的输入
  • cin >> 输入,但遇到空格会停止。
  • cin.getline() 可以输入带空格的整行。
#include <iostream>
using namespace std;

int main() {
    char name[50];
    cout << "请输入你的名字(无空格):";
    cin >> name;                // 只能输入一个单词
    cout << "你好," << name << endl;

    // 清空输入缓冲区(因为后面要用getline,之前cin会留下换行符)
    cin.ignore();

    char sentence[100];
    cout << "请输入一句话(可带空格):";
    cin.getline(sentence, 100); // 读取整行,最多99个字符
    cout << "你输入的是:" << sentence << endl;

    return 0;
}
string类的输入
  • cin >> 输入,同样遇空格停止。
  • getline(cin, 字符串变量) 输入整行。
#include <iostream>
#include <string>
using namespace std;

int main() {
    string name, sentence;

    cout << "请输入你的名字:";
    cin >> name;
    cout << "你好," << name << endl;

    cin.ignore();   // 忽略输入缓冲区中的换行符

    cout << "请输入一句话:";
    getline(cin, sentence);   // 读取整行
    cout << "你输入的是:" << sentence << endl;

    return 0;
}

6.2.4 字符串结束符‘\0’

C风格字符串以 '\0'(空字符,ASCII码0)作为结束标志。它告诉程序字符串在哪里结束。

为什么需要 '\0'

因为字符数组的长度可能大于字符串的实际长度,如果没有结束符,程序就不知道到哪里是字符串的结尾。比如:

char str[10] = "Hello";   // 实际存储:H e l l o \0 ? ? ? ?

当输出 str 时,函数会从第一个字符开始一直输出直到遇到 '\0'。如果忘了加 '\0',可能会输出乱码直到遇到内存中的某个0。

手动添加 '\0'

如果自己逐个字符赋值,必须手动加上 '\0'

char str[5];
str[0] = 'C';
str[1] = '+';
str[2] = '+';
str[3] = '\0';   // 必须加!
cout << str;     // 输出 "C++"

如果忘记加,cout 会继续向后输出内存中的内容,直到偶然遇到0,可能导致程序崩溃或输出乱码。

6.2.5 字符串常用函数

C语言提供了一些处理字符串的函数,它们定义在 <cstring> 头文件中。注意这些函数都用于C风格字符串(字符数组)。

函数 作用
strlen(s) 返回字符串s的长度(不包括\0
strcpy(dest, src) 将src复制到dest
strcat(dest, src) 将src连接到dest的末尾
strcmp(s1, s2) 比较s1和s2,相等返回0,s1s2返回正数
strchr(s, c) 在s中查找字符c第一次出现的位置,返回指针
strstr(s1, s2) 在s1中查找子串s2,返回指针
示例代码
#include <iostream>
#include <cstring>   // 字符串函数
using namespace std;

int main() {
    char s1[20] = "Hello";
    char s2[20] = "World";
    char s3[40];

    // 求长度
    cout << "s1长度:" << strlen(s1) << endl;   // 5

    // 复制
    strcpy(s3, s1);   // s3 = "Hello"
    cout << "s3 = " << s3 << endl;

    // 连接
    strcat(s3, " ");  // 加一个空格
    strcat(s3, s2);   // s3 = "Hello World"
    cout << "连接后:" << s3 << endl;

    // 比较
    if (strcmp(s1, s2) == 0) {
        cout << "s1和s2相等" << endl;
    } else {
        cout << "s1和s2不相等" << endl;
    }

    return 0;
}

注意:使用这些函数时,要确保目标数组足够大,否则会溢出。

6.2.6 string类

C++提供了一个更安全、更方便的字符串类型:string。它包含在头文件 <string> 中。使用 string 类可以像普通变量一样操作字符串,不需要担心数组大小和结束符。

定义和初始化
#include <string>
string s1;                // 空字符串
string s2 = "Hello";      // 直接赋值
string s3("World");       // 构造函数
string s4 = s2;           // 复制
string s5 = s2 + " " + s3; // 连接
常用操作
  • 长度s.length()s.size()
  • 访问字符s[i],下标从0开始
  • 赋值s = "new value";
  • 连接:用 ++=
  • 比较:直接用 ==!=<> 等运算符
  • 输入cin >> sgetline(cin, s)
  • 输出cout << s
示例代码
#include <iostream>
#include <string>
using namespace std;

int main() {
    string s1 = "Hello";
    string s2 = "World";
    string s3;

    // 连接
    s3 = s1 + " " + s2;
    cout << "s3 = " << s3 << endl;   // Hello World

    // 长度
    cout << "s3的长度:" << s3.length() << endl;   // 11

    // 访问字符
    for (int i = 0; i < s3.length(); i++) {
        cout << s3[i] << " ";   // H e l l o   W o r l d
    }
    cout << endl;

    // 比较
    if (s1 == s2) {
        cout << "相等" << endl;
    } else {
        cout << "不相等" << endl;
    }

    // 子串
    string sub = s3.substr(6, 5);   // 从下标6开始取5个字符
    cout << "子串:" << sub << endl; // World

    // 查找
    int pos = s3.find("World");
    if (pos != string::npos) {
        cout << "找到World,位置在:" << pos << endl;
    }

    return 0;
}
string类的更多成员函数
  • s.substr(pos, len):返回从pos开始长度为len的子串。
  • s.find(str):查找子串,返回第一次出现的位置,如果找不到返回 string::npos
  • s.replace(pos, len, str):将从pos开始长度为len的子串替换为str。
  • s.insert(pos, str):在pos位置插入str。
  • s.erase(pos, len):删除从pos开始的len个字符。
  • s.empty():判断是否为空。
  • s.clear():清空字符串。

6.2.7 阶段性编程练习(字符串基础)

  1. 练习1:输入一个字符,判断它是字母、数字还是其他字符,并输出对应信息。
  2. 练习2:输入一行字符串(可含空格),统计其中字母、数字、空格的个数。
  3. 练习3:输入一个字符串,将其中的小写字母转为大写,大写字母转为小写,其他字符不变,输出结果。
  4. 练习4:用C风格字符串实现字符串反转(不使用string类的reverse函数)。
  5. 练习5:用string类实现:输入两个字符串,连接后输出,并输出长度。

6.3 编程实例讲解

这里我们通过几个综合实例,进一步巩固字符串的操作。

实例1:统计单词个数(使用string)

题目:输入一行英文句子,统计其中有多少个单词(单词之间用空格分隔)。

#include <iostream>
#include <string>
using namespace std;

int main() {
    string s;
    cout << "请输入一句英文:";
    getline(cin, s);   // 读取整行

    int count = 0;
    bool inWord = false;   // 标记是否正在一个单词中

    for (int i = 0; i < s.length(); i++) {
        if (s[i] != ' ') {          // 如果当前字符不是空格
            if (!inWord) {          // 并且之前不在单词中,说明新单词开始
                count++;
                inWord = true;
            }
        } else {                     // 遇到空格,表示单词结束
            inWord = false;
        }
    }

    cout << "单词个数:" << count << endl;
    return 0;
}

实例2:判断回文串

题目:输入一个字符串(忽略空格和标点,只考虑字母和数字),判断它是否是回文(正读反读一样,比如 “madam”、”12321”)。

#include <iostream>
#include <string>
#include <cctype>   // 字符处理函数
using namespace std;

int main() {
    string s;
    cout << "请输入一个字符串:";
    getline(cin, s);

    // 先过滤掉非字母数字字符,并转为小写
    string filtered;
    for (int i = 0; i < s.length(); i++) {
        if (isalnum(s[i])) {          // 如果是字母或数字
            filtered += tolower(s[i]); // 转为小写后加入
        }
    }

    // 判断回文
    bool isPalindrome = true;
    int len = filtered.length();
    for (int i = 0; i < len / 2; i++) {
        if (filtered[i] != filtered[len - 1 - i]) {
            isPalindrome = false;
            break;
        }
    }

    if (isPalindrome) {
        cout << "是回文" << endl;
    } else {
        cout << "不是回文" << endl;
    }

    return 0;
}

实例3:凯撒密码(加密)

题目:输入一个字符串和一个偏移量k,将字符串中的每个英文字母替换为字母表中后移k位的字母(循环,例如z后移1位变成a),其他字符不变,输出加密后的字符串。

#include <iostream>
#include <string>
using namespace std;

int main() {
    string s;
    int k;
    cout << "请输入要加密的字符串:";
    getline(cin, s);
    cout << "请输入偏移量:";
    cin >> k;

    for (int i = 0; i < s.length(); i++) {
        char ch = s[i];
        if (ch >= 'a' && ch <= 'z') {
            ch = 'a' + (ch - 'a' + k) % 26;
        } else if (ch >= 'A' && ch <= 'Z') {
            ch = 'A' + (ch - 'A' + k) % 26;
        }
        s[i] = ch;
    }

    cout << "加密后的字符串:" << s << endl;
    return 0;
}

实例4:字符串排序(按字典序)

题目:输入若干个人名(字符串),按字典序从小到大排序后输出。

#include <iostream>
#include <string>
using namespace std;

int main() {
    const int N = 5;
    string names[N];
    cout << "请输入" << N << "个人名:" << endl;
    for (int i = 0; i < N; i++) {
        cin >> names[i];   // 假设名字不含空格
    }

    // 冒泡排序
    for (int i = 0; i < N - 1; i++) {
        for (int j = 0; j < N - 1 - i; j++) {
            if (names[j] > names[j + 1]) {   // string可以直接比较
                string temp = names[j];
                names[j] = names[j + 1];
                names[j + 1] = temp;
            }
        }
    }

    cout << "排序后的名字:" << endl;
    for (int i = 0; i < N; i++) {
        cout << names[i] << endl;
    }

    return 0;
}

6.4 第6章编程作业

恭喜你学完了字符串!现在来挑战几个综合题目,检验一下学习成果。

作业1:统计字符串中每个字母出现的次数

输入一行字符串(可含空格),统计其中26个英文字母(不区分大小写)各自出现的次数,并输出。忽略非字母字符。

作业2:简单密码验证

设定一个密码字符串(如 “C++2024”),让用户输入密码,最多允许输入3次,如果正确显示“欢迎”,否则显示“密码错误”并提示剩余次数,3次错误后显示“账户锁定”。

作业3:手机键盘数字映射

在老式手机键盘上,字母映射到数字:2:abc, 3:def, 4:ghi, 5:jkl, 6:mno, 7:pqrs, 8:tuv, 9:wxyz。输入一个单词(只含字母),输出对应的数字串。例如输入 “hello”,输出 “43556”。

作业4:字符串去重

输入一个字符串,去掉其中重复的字符(只保留第一次出现的字符),输出结果。例如输入 “hello world”,输出 “helo wrd”(注意空格也要保留,但重复的空格只保留一个?可以自己定义规则)。

作业5:单词反转

输入一句英文,将句子中的单词顺序反转,但单词内部的字母顺序不变。例如输入 “I love C++”,输出 “C++ love I”。提示:可以用字符串流或手动分割单词。