C++ Primer 第3章:字符串、向量和数组

C++ Primer 第3章:字符串、向量和数组


3.1 命名空间的 using 声明

3.1.1 using 声明的使用

cpp 复制代码
// using_demo.cpp -- using声明
#include <iostream>
#include <string>

// 方式1:using声明(推荐,精确引入)
using std::cin;
using std::cout;
using std::endl;
using std::string;

// 方式2:using编译指令(不推荐在头文件中使用)
// using namespace std;

int main()
{
    // 有了using声明,不需要写 std::
    string line;
    cout << "请输入一行文字:";
    getline(cin, line);
    cout << "你输入了:" << line << endl;

    return 0;
}

⚠️ 注意

  • 头文件中不应该 使用 using 编译指令,会污染包含该头文件的所有文件
  • 每个 using 声明只引入一个名字
  • 函数内的 using 声明只在该函数内有效

3.2 标准库类型 string

3.2.1 string 的定义和初始化

cpp 复制代码
// string_init.cpp -- string的初始化方式
#include <iostream>
#include <string>

int main()
{
    using namespace std;

    // 各种初始化方式
    string s1;              // 默认初始化:空字符串
    string s2("Hello");     // 直接初始化:C字符串
    string s3 = "Hello";    // 拷贝初始化:等价于s2
    string s4(s2);          // 直接初始化:拷贝s2
    string s5 = s2;         // 拷贝初始化:等价于s4
    string s6(5, 'a');      // 直接初始化:5个'a' → "aaaaa"
    string s7(s2, 1, 3);    // 从s2第1位开始取3个字符:"ell"

    cout << "s1 = \"" << s1 << "\"" << endl;
    cout << "s2 = \"" << s2 << "\"" << endl;
    cout << "s6 = \"" << s6 << "\"" << endl;
    cout << "s7 = \"" << s7 << "\"" << endl;

    // 直接初始化 vs 拷贝初始化
    // 直接初始化:string s(args)
    // 拷贝初始化:string s = val(使用=号)

    return 0;
}

3.2.2 string 的操作

cpp 复制代码
// string_ops.cpp -- string的常用操作
#include <iostream>
#include <string>

int main()
{
    using namespace std;

    string s = "Hello, World!";

    // ===== 基本操作 =====
    cout << "内容:" << s << endl;
    cout << "长度:" << s.size()   << endl;   // 13(返回size_type,无符号类型)
    cout << "长度:" << s.length() << endl;   // 同上
    cout << "是否空:" << boolalpha << s.empty() << endl;

    // ⚠️ size() 返回 string::size_type(无符号类型)
    // 不要与 int 混用,可能导致意外结果
    string::size_type len = s.size();
    // int n = -1;
    // if (n < s.size())   // 危险!n被转为无符号,-1变成很大的数

    // ===== 比较操作 =====
    string s1 = "apple", s2 = "banana";
    cout << "\n比较:" << endl;
    cout << "apple < banana : " << (s1 < s2) << endl;   // true
    cout << "apple == apple : " << (s1 == s1) << endl;  // true
    // 比较规则:逐字符比较,大小写敏感

    // ===== 拼接操作 =====
    string hello = "Hello";
    string world = "World";
    string hw = hello + ", " + world + "!";
    cout << "\n拼接:" << hw << endl;

    // ⚠️ 字符串字面值不能直接相加
    // string s = "Hello" + ", ";   // ❌ 错误!两个字面值不能相加
    string s3 = "Hello";
    string s4 = s3 + ", " + "World";   // ✅ 左边有string对象

    // ===== 访问字符 =====
    cout << "\n访问字符:" << endl;
    cout << "s[0] = " << s[0] << endl;       // 'H'(不检查边界)
    cout << "s.at(0) = " << s.at(0) << endl; // 'H'(检查边界,越界抛异常)
    cout << "front = " << s.front() << endl; // 'H'
    cout << "back  = " << s.back()  << endl; // '!'

    // 修改字符
    s[0] = 'h';
    cout << "修改后:" << s << endl;

    return 0;
}

3.2.3 处理 string 中的字符(cctype)

cpp 复制代码
// string_chars.cpp -- 处理string中的字符
#include <iostream>
#include <string>
#include <cctype>   // 字符处理函数

int main()
{
    using namespace std;

    string s = "Hello, World! 123";

    // ===== 范围for循环处理每个字符 =====
    cout << "统计各类字符:" << endl;
    int letters = 0, digits = 0, spaces = 0, others = 0;

    for (auto c : s)   // c 是 char 类型的副本
    {
        if (isalpha(c))      letters++;
        else if (isdigit(c)) digits++;
        else if (isspace(c)) spaces++;
        else                 others++;
    }
    cout << "字母:" << letters << " 数字:" << digits
         << " 空格:" << spaces << " 其他:" << others << endl;

    // ===== 通过引用修改字符 =====
    string str = "Hello World";
    for (auto& c : str)   // c 是引用,可以修改
        c = toupper(c);
    cout << "转大写:" << str << endl;

    // ===== 使用下标访问 =====
    string word = "hello";
    // 将第一个字符转为大写
    if (!word.empty())
        word[0] = toupper(word[0]);
    cout << "首字母大写:" << word << endl;

    // ===== 常用 cctype 函数 =====
    char ch = 'A';
    cout << "\ncctype函数示例(字符'" << ch << "'):" << endl;
    cout << "isalpha: " << boolalpha << (bool)isalpha(ch) << endl;
    cout << "isupper: " << (bool)isupper(ch) << endl;
    cout << "islower: " << (bool)islower(ch) << endl;
    cout << "isdigit: " << (bool)isdigit(ch) << endl;
    cout << "tolower: " << (char)tolower(ch) << endl;

    return 0;
}

常用 cctype 函数:

函数 说明
isalpha(c) c 是字母时为真
isdigit(c) c 是数字时为真
isalnum(c) c 是字母或数字时为真
isspace(c) c 是空白(空格、制表符、换行等)时为真
isupper(c) c 是大写字母时为真
islower(c) c 是小写字母时为真
ispunct(c) c 是标点符号时为真
toupper(c) 返回 c 的大写形式
tolower(c) 返回 c 的小写形式

3.3 标准库类型 vector

3.3.1 vector 的定义和初始化

cpp 复制代码
// vector_init.cpp -- vector的初始化
#include <iostream>
#include <vector>
#include <string>

int main()
{
    using namespace std;

    // vector 是模板,需要指定元素类型
    vector<int>    v1;              // 空vector
    vector<int>    v2(10);          // 10个元素,每个值为0
    vector<int>    v3(10, 1);       // 10个元素,每个值为1
    vector<int>    v4 = {1,2,3,4,5}; // 列表初始化
    vector<int>    v5{1,2,3,4,5};   // 等价于v4
    vector<int>    v6(v4);          // 拷贝v4
    vector<string> vs1{"Hello", "World", "C++"};
    vector<string> vs2(3, "hi");    // 3个"hi"

    // 圆括号 vs 花括号的区别
    vector<int> v7(3);    // 3个元素,值为0
    vector<int> v8{3};    // 1个元素,值为3

    vector<int> v9(3, 1);  // 3个元素,值为1
    vector<int> v10{3, 1}; // 2个元素:3和1

    cout << "v7.size() = " << v7.size() << endl;   // 3
    cout << "v8.size() = " << v8.size() << endl;   // 1
    cout << "v9.size() = " << v9.size() << endl;   // 3
    cout << "v10.size() = " << v10.size() << endl; // 2

    // 打印 v4
    cout << "v4: ";
    for (auto x : v4) cout << x << " ";
    cout << endl;

    return 0;
}

3.3.2 vector 的操作

cpp 复制代码
// vector_ops.cpp -- vector的常用操作
#include <iostream>
#include <vector>
#include <string>

int main()
{
    using namespace std;

    vector<int> v;

    // ===== 添加元素 =====
    // push_back:在末尾添加元素(最常用)
    for (int i = 0; i < 10; i++)
        v.push_back(i * i);   // 0,1,4,9,16,25,36,49,64,81

    // ===== 基本属性 =====
    cout << "大小:" << v.size()  << endl;   // 10
    cout << "是否空:" << boolalpha << v.empty() << endl;

    // ===== 访问元素 =====
    cout << "v[0] = " << v[0] << endl;       // 0(不检查边界)
    cout << "v.at(0) = " << v.at(0) << endl; // 0(检查边界)
    cout << "front = " << v.front() << endl; // 0
    cout << "back  = " << v.back()  << endl; // 81

    // ===== 遍历 =====
    cout << "\n遍历方式:" << endl;

    // 方式1:范围for(推荐,只读)
    cout << "范围for:";
    for (const auto& x : v) cout << x << " ";
    cout << endl;

    // 方式2:下标
    cout << "下标:";
    for (size_t i = 0; i < v.size(); i++) cout << v[i] << " ";
    cout << endl;

    // 方式3:迭代器
    cout << "迭代器:";
    for (auto it = v.begin(); it != v.end(); ++it) cout << *it << " ";
    cout << endl;

    // ===== 修改元素 =====
    for (auto& x : v) x *= 2;   // 每个元素乘2
    cout << "\n乘2后:";
    for (auto x : v) cout << x << " ";
    cout << endl;

    // ===== 其他操作 =====
    v.pop_back();   // 删除最后一个元素
    cout << "pop_back后大小:" << v.size() << endl;

    // ⚠️ 不能在范围for循环中向vector添加元素!
    // 会使迭代器失效

    // ===== vector 的比较 =====
    vector<int> a = {1, 2, 3};
    vector<int> b = {1, 2, 4};
    cout << "\na < b : " << (a < b) << endl;   // true(逐元素比较)

    return 0;
}

3.3.3 vector 的增长机制

cpp 复制代码
// vector_growth.cpp -- vector的增长机制
#include <iostream>
#include <vector>

int main()
{
    using namespace std;

    vector<int> v;
    cout << "初始容量:" << v.capacity() << endl;

    for (int i = 0; i < 20; i++)
    {
        v.push_back(i);
        cout << "size=" << v.size()
             << " capacity=" << v.capacity() << endl;
    }

    // reserve:预分配容量(避免频繁扩容)
    vector<int> v2;
    v2.reserve(100);
    cout << "\nreserve(100)后容量:" << v2.capacity() << endl;

    // resize:改变大小
    v2.resize(10, 0);   // 大小变为10,新元素初始化为0
    cout << "resize(10)后大小:" << v2.size() << endl;

    return 0;
}

💡 vector 的增长策略

  • 当容量不足时,vector 通常将容量翻倍
  • size():当前元素数量
  • capacity():当前分配的内存能容纳的元素数量
  • reserve(n):预分配至少 n 个元素的空间(不改变 size)
  • resize(n):改变 size,可能改变 capacity

3.4 迭代器

3.4.1 迭代器的基本使用

cpp 复制代码
// iterator_demo.cpp -- 迭代器基础
#include <iostream>
#include <string>
#include <vector>

int main()
{
    using namespace std;

    string s = "Hello, World!";
    vector<int> v = {1, 2, 3, 4, 5};

    // ===== 获取迭代器 =====
    // begin():指向第一个元素
    // end():指向最后一个元素的下一位置(尾后迭代器)
    auto b = s.begin();   // string::iterator
    auto e = s.end();     // string::iterator

    // ===== 解引用和递增 =====
    cout << "第一个字符:" << *b << endl;   // 'H'
    ++b;
    cout << "第二个字符:" << *b << endl;   // 'e'

    // ===== 遍历 =====
    cout << "遍历string:";
    for (auto it = s.begin(); it != s.end(); ++it)
        cout << *it;
    cout << endl;

    // ===== 修改元素(非const迭代器)=====
    for (auto it = s.begin(); it != s.end(); ++it)
        *it = toupper(*it);
    cout << "转大写:" << s << endl;

    // ===== const 迭代器(只读)=====
    // cbegin() 和 cend() 返回 const_iterator
    for (auto it = v.cbegin(); it != v.cend(); ++it)
        cout << *it << " ";
    cout << endl;

    // ===== 迭代器运算(随机访问迭代器)=====
    auto mid = v.begin() + v.size() / 2;
    cout << "中间元素:" << *mid << endl;

    // 迭代器相减得到距离
    auto dist = v.end() - v.begin();
    cout << "距离:" << dist << endl;   // 5

    return 0;
}

3.4.2 迭代器类型与操作

cpp 复制代码
// iterator_types.cpp -- 迭代器类型
#include <iostream>
#include <vector>
#include <string>

int main()
{
    using namespace std;

    vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    // iterator:可读可写
    vector<int>::iterator it1 = v.begin();

    // const_iterator:只读
    vector<int>::const_iterator it2 = v.cbegin();

    // auto 简化类型名
    auto it3 = v.begin();    // vector<int>::iterator
    auto it4 = v.cbegin();   // vector<int>::const_iterator

    // ===== 迭代器运算(string和vector支持)=====
    // it + n:向后移动n步
    // it - n:向前移动n步
    // it1 - it2:两个迭代器之间的距离
    // it1 < it2:比较位置

    // 二分查找示例
    auto beg = v.begin(), end = v.end();
    auto mid = beg + (end - beg) / 2;
    int target = 7;

    while (mid != end && *mid != target)
    {
        if (target < *mid)
            end = mid;
        else
            beg = mid + 1;
        mid = beg + (end - beg) / 2;
    }

    if (mid != v.end() && *mid == target)
        cout << "找到 " << target << ",位置:"
             << (mid - v.begin()) << endl;

    // ===== 反向迭代器 =====
    cout << "反向遍历:";
    for (auto it = v.rbegin(); it != v.rend(); ++it)
        cout << *it << " ";
    cout << endl;

    return 0;
}

迭代器操作总结:

操作 说明
*it 解引用,返回迭代器所指元素的引用
it->mem 等价于 (*it).mem
++it 令 it 指向下一个元素
--it 令 it 指向上一个元素
it1 == it2 判断两个迭代器是否相等
it + n 向后移动 n 步(随机访问迭代器)
it - n 向前移动 n 步(随机访问迭代器)
it1 - it2 两迭代器间的距离(随机访问迭代器)

3.5 数组

3.5.1 数组的定义和初始化

cpp 复制代码
// array_init.cpp -- 数组的定义和初始化
#include <iostream>

int main()
{
    using namespace std;

    // 数组大小必须是常量表达式
    constexpr int sz = 5;

    // 各种初始化方式
    int    a1[10];              // 未初始化(局部数组,值未定义)
    int    a2[sz] = {0,1,2,3,4}; // 列表初始化
    int    a3[]   = {0,1,2,3,4}; // 省略大小,自动推断为5
    int    a4[5]  = {0,1,2};    // 部分初始化:{0,1,2,0,0}
    int    a5[5]  = {};         // 全部初始化为0
    string sa[3]  = {"hi", "bye", "now"};

    // 字符数组的特殊性
    char c1[] = {'C', '+', '+'};        // 大小为3,没有空字符
    char c2[] = {'C', '+', '+', '\0'};  // 大小为4,有空字符
    char c3[] = "C++";                  // 大小为4,自动添加'\0'
    // const char c4[3] = "C++";        // ❌ 错误:空间不够

    cout << "a2: ";
    for (int x : a2) cout << x << " ";
    cout << endl;

    cout << "a4: ";
    for (int x : a4) cout << x << " ";
    cout << endl;

    cout << "c3: " << c3 << endl;

    // ⚠️ 数组不能拷贝和赋值
    // int a6[] = a2;   // ❌ 错误:不能用数组初始化另一个数组
    // a1 = a2;         // ❌ 错误:不能把数组赋值给另一个数组

    return 0;
}

3.5.2 数组的访问与遍历

cpp 复制代码
// array_access.cpp -- 数组的访问
#include <iostream>
#include <string>

int main()
{
    using namespace std;

    int scores[5] = {85, 92, 78, 96, 88};

    // ===== 下标访问 =====
    cout << "scores[0] = " << scores[0] << endl;
    cout << "scores[4] = " << scores[4] << endl;

    // ===== 范围for遍历 =====
    cout << "范围for:";
    for (const auto& s : scores)
        cout << s << " ";
    cout << endl;

    // ===== 指针遍历 =====
    // 数组名是指向第一个元素的指针
    int* p = scores;   // 等价于 int* p = &scores[0]
    cout << "指针遍历:";
    for (int i = 0; i < 5; i++)
        cout << *(p + i) << " ";
    cout << endl;

    // ===== begin() 和 end()(C++11)=====
    // 使用标准库函数获取数组的首尾指针
    int* beg = begin(scores);
    int* end = end(scores);
    cout << "begin/end遍历:";
    for (int* it = beg; it != end; ++it)
        cout << *it << " ";
    cout << endl;

    // ===== 计算数组大小 =====
    int sz = end(scores) - begin(scores);   // 5
    // 或者:
    int sz2 = sizeof(scores) / sizeof(scores[0]);   // 5
    cout << "数组大小:" << sz << endl;

    return 0;
}

3.5.3 指针与数组

cpp 复制代码
// pointer_array.cpp -- 指针与数组的关系
#include <iostream>

int main()
{
    using namespace std;

    int ia[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

    // 数组名就是指向第一个元素的指针
    int* p = ia;   // 等价于 int* p = &ia[0]

    // 指针算术
    cout << "*p     = " << *p     << endl;   // 0
    cout << "*(p+1) = " << *(p+1) << endl;   // 1
    cout << "p[2]   = " << p[2]   << endl;   // 2(下标运算)

    // 指针递增
    ++p;
    cout << "*p(递增后)= " << *p << endl;   // 1

    // 指针相减(得到距离)
    int* p2 = ia + 5;
    ptrdiff_t diff = p2 - ia;   // ptrdiff_t:有符号类型,表示指针差值
    cout << "p2 - ia = " << diff << endl;   // 5

    // 指针比较
    cout << "ia < p2 : " << boolalpha << (ia < p2) << endl;   // true

    // 下标可以是负数(对指针有效,对数组名无效)
    int* mid = ia + 5;
    cout << "mid[-1] = " << mid[-1] << endl;   // 4(ia[4])
    cout << "mid[0]  = " << mid[0]  << endl;   // 5(ia[5])

    // ===== C风格字符串 =====
    const char* cp = "Hello";
    while (*cp)   // 利用'\0'结尾
    {
        cout << *cp;
        ++cp;
    }
    cout << endl;

    return 0;
}

3.5.4 多维数组

cpp 复制代码
// multidim_array.cpp -- 多维数组
#include <iostream>

int main()
{
    using namespace std;

    // 定义二维数组(3行4列)
    int ia[3][4] = {
        {0,  1,  2,  3},   // 第0行
        {4,  5,  6,  7},   // 第1行
        {8,  9, 10, 11}    // 第2行
    };

    // 等价的初始化(不分行)
    int ib[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};

    // 部分初始化
    int ic[3][4] = {{0}, {4}, {8}};   // 每行只初始化第一个元素

    // ===== 访问元素 =====
    cout << "ia[1][2] = " << ia[1][2] << endl;   // 6

    // ===== 遍历(范围for)=====
    cout << "范围for遍历:" << endl;
    for (const auto& row : ia)      // row 是 int(&)[4],必须用引用!
    {
        for (const auto& col : row)
            cout << col << "\t";
        cout << endl;
    }

    // ===== 遍历(下标)=====
    cout << "\n下标遍历:" << endl;
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 4; j++)
            cout << ia[i][j] << "\t";
        cout << endl;
    }

    // ===== 遍历(指针)=====
    cout << "\n指针遍历:" << endl;
    for (int (*row)[4] = begin(ia); row != end(ia); ++row)
    {
        for (int* col = begin(*row); col != end(*row); ++col)
            cout << *col << "\t";
        cout << endl;
    }

    // 使用 auto 简化指针类型
    cout << "\nauto指针遍历:" << endl;
    for (auto p = begin(ia); p != end(ia); ++p)
    {
        for (auto q = begin(*p); q != end(*p); ++q)
            cout << *q << "\t";
        cout << endl;
    }

    // ===== 类型别名简化 =====
    using int_array = int[4];   // int_array 是 int[4] 的别名
    for (int_array& row : ia)
    {
        for (int col : row)
            cout << col << " ";
        cout << endl;
    }

    return 0;
}

⚠️ 多维数组范围for的注意事项

  • 除最内层循环外,其他循环的控制变量必须是引用类型
  • 否则数组会退化为指针,无法继续用范围for遍历

3.6 数组与 vector 的对比

cpp 复制代码
// array_vs_vector.cpp -- 数组与vector对比
#include <iostream>
#include <vector>
#include <string>
#include <cstring>   // C字符串函数

int main()
{
    using namespace std;

    // ===== C风格字符串 vs string =====
    // C风格字符串(字符数组)
    char ca[] = "Hello";
    char cb[] = "World";

    // C字符串操作需要函数
    cout << "strlen: " << strlen(ca) << endl;
    // strcat(ca, cb);   // 危险!可能越界
    char cc[20];
    strcpy(cc, ca);
    strcat(cc, " ");
    strcat(cc, cb);
    cout << "C字符串拼接:" << cc << endl;

    // string(推荐)
    string sa = "Hello";
    string sb = "World";
    string sc = sa + " " + sb;   // 简单安全
    cout << "string拼接:" << sc << endl;

    // ===== 数组 vs vector =====
    // 数组:固定大小,不能动态增长
    int arr[5] = {1, 2, 3, 4, 5};

    // vector:动态大小,功能丰富
    vector<int> vec = {1, 2, 3, 4, 5};
    vec.push_back(6);   // 动态增长

    // ===== 用数组初始化vector =====
    int int_arr[] = {0, 1, 2, 3, 4, 5};
    vector<int> ivec(begin(int_arr), end(int_arr));
    cout << "从数组初始化vector:";
    for (auto x : ivec) cout << x << " ";
    cout << endl;

    // 只取数组的一部分
    vector<int> subvec(int_arr + 1, int_arr + 4);   // {1,2,3}
    cout << "子数组:";
    for (auto x : subvec) cout << x << " ";
    cout << endl;

    return 0;
}

数组 vs vector 对比:

特性 数组 vector
大小 固定(编译时确定) 动态(运行时可变)
初始化 可以列表初始化 可以列表初始化
拷贝/赋值 ❌ 不支持 ✅ 支持
大小查询 sizeof/end-begin .size()
边界检查 ❌ 无([] .at()
内存管理 自动(栈)或手动(堆) 自动
推荐程度 特殊场景 通常推荐

3.7 综合示例:文本统计分析

cpp 复制代码
// text_analysis.cpp -- 综合示例:文本统计分析
#include <iostream>
#include <string>
#include <vector>
#include <cctype>
#include <algorithm>
#include <map>

int main()
{
    using namespace std;

    // 模拟输入文本
    vector<string> lines = {
        "Hello World this is a test",
        "C++ programming is fun and powerful",
        "Vectors and strings are very useful",
        "Practice makes perfect in coding"
    };

    // ===== 统计信息 =====
    int totalChars  = 0;
    int totalWords  = 0;
    int totalLetters = 0;
    int totalDigits  = 0;
    int totalSpaces  = 0;

    vector<string> allWords;   // 收集所有单词

    for (const auto& line : lines)
    {
        totalChars += line.size();

        // 统计字符类型
        for (char c : line)
        {
            if (isalpha(c))      totalLetters++;
            else if (isdigit(c)) totalDigits++;
            else if (isspace(c)) totalSpaces++;
        }

        // 提取单词
        string word;
        for (char c : line)
        {
            if (isalpha(c))
                word += tolower(c);   // 转小写
            else if (!word.empty())
            {
                allWords.push_back(word);
                totalWords++;
                word.clear();
            }
        }
        if (!word.empty())
        {
            allWords.push_back(word);
            totalWords++;
        }
    }

    // ===== 统计词频 =====
    map<string, int> wordFreq;
    for (const auto& w : allWords)
        wordFreq[w]++;

    // ===== 输出结果 =====
    cout << "===== 文本统计 =====" << endl;
    cout << "总行数:" << lines.size()  << endl;
    cout << "总字符:" << totalChars    << endl;
    cout << "总单词:" << totalWords    << endl;
    cout << "字母数:" << totalLetters  << endl;
    cout << "数字数:" << totalDigits   << endl;
    cout << "空格数:" << totalSpaces   << endl;

    cout << "\n===== 词频统计(出现2次以上)=====" << endl;
    for (const auto& [word, count] : wordFreq)
        if (count >= 2)
            cout << word << ": " << count << " 次" << endl;

    // ===== 最长单词 =====
    auto longest = max_element(allWords.begin(), allWords.end(),
        [](const string& a, const string& b) {
            return a.size() < b.size();
        });
    if (longest != allWords.end())
        cout << "\n最长单词:" << *longest
             << "(" << longest->size() << " 个字母)" << endl;

    // ===== 按字母顺序排序并去重 =====
    sort(allWords.begin(), allWords.end());
    allWords.erase(unique(allWords.begin(), allWords.end()),
                   allWords.end());

    cout << "\n所有不重复单词(字母序):" << endl;
    for (size_t i = 0; i < allWords.size(); i++)
    {
        cout << allWords[i];
        if (i < allWords.size() - 1) cout << ", ";
    }
    cout << endl;

    return 0;
}

📝 第3章知识点总结

知识点 核心要点
using 声明 using std::cin 精确引入,头文件中不用 using namespace
string 初始化 直接初始化(括号)vs 拷贝初始化(等号),string(n, c) 重复字符
string::size_type size() 返回无符号类型,不要与 int 混用
string 拼接 + 两侧至少一个 string 对象,字面值不能直接相加
范围for修改 修改元素时循环变量必须是引用 auto&
vector 初始化 (n) 创建n个元素,{n} 创建含n的列表,注意区别
push_back 运行时动态添加元素,不要在范围for中添加元素
迭代器 begin()/end()cbegin()/cend()(只读),!= 判断结束
迭代器失效 向 vector 添加元素后,所有迭代器可能失效
数组大小 必须是常量表达式,不能拷贝赋值,可用 begin()/end()
数组退化 数组名在大多数表达式中退化为指向首元素的指针
多维数组范围for 除最内层外,控制变量必须是引用,否则退化为指针
C字符串 \0 结尾,操作需要 <cstring> 函数,推荐用 string 替代
数组→vector vector<int> v(begin(arr), end(arr)) 用数组初始化 vector
相关推荐
兰令水1 小时前
leecodecode【反前后指针】【2026.5.31打卡-java版本】
java·开发语言
Dovis(誓平步青云)2 小时前
《QT学习第四篇:常见事件与UDP、TCP、文件系统、(锁、信号量、条件变量》
c语言·开发语言·汇编·qt
code monkey.2 小时前
【Linux之旅】Linux 应用层自定义协议与序列化:从粘包问题到网络计算器
linux·网络·c++
草莓熊Lotso2 小时前
【Linux网络】深入理解 HTTP 协议(二):从协议格式到手写工业级 HTTP 服务器
linux·运维·服务器·网络·c++·http
isyangli_blog10 小时前
OpenDayLight (Carbon 版本) 启动与组件安装
开发语言·php
vb20081110 小时前
FastAPI APIRouter
开发语言·python
Benszen10 小时前
KVM虚拟化解决方案
开发语言·perl
会编程的土豆10 小时前
Go 语言反射(Reflection)详解
开发语言·后端·golang
東雪木10 小时前
多线程与并发编程 专属复习笔记
java·开发语言·笔记·java面试