cppPrimer学习-9th

Posted zongzi10010

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了cppPrimer学习-9th相关的知识,希望对你有一定的参考价值。


title: cppPrimer学习9th
date: 2020/1/3 10:37:05
toc: true
---

cppPrimer学习9th

源代码

https://github.com/Layty/CppPrimer

知识点

我的小模版

#include <forward_list>
#include <iostream>
#include <list>
#include <vector>
using namespace std;

template <typename T> 
void print(T src)
{
    for (auto ch : src) 
        cout << ch <<",";
    cout<<endl;
}

int main(int argc, const char** argv)
{

    while(1);
}
  • resize改变的是size,reserve表示的是容量的预分配

  • 在string转数字的时候,使用if(ch.find_first_of("0123456789")!=string::npos)后再来处理数字避免异常等,可以看练习题9.50.转换数字的字符串第一个字符要是合法的+-.0123456789

  • string用char来构造,string(1,ch)

练习题

9.1

9.1 对于下面的程序任务,vector, deque和list哪种容器最为合适?解释你选择的理由。如果没有哪一种容器优于其它容器,也请解释理由。

读取固定数量的单词,将它们按字典序插入到容器中。我们将在下一章看到,关联容器更适合这个问题。
读取未知数量的单词,总是将新单词插入到末尾。删除操作在头部进行。
从一个文件中读取未知数量的整数。将这些整数排序,然后打印到标准输出。
  1. 别人的答案使用list,因为涉及到中间插入,但是按照书本的解释,我觉得可以先使用vector存放,再使用sort排序,这里作者有写固定数量

    技术图片

  2. 使用deque
  3. 因为整数是小容量大小的数据元素,这里使用vector,再使用sort

9.2

定义一个list对象,其元素类型是int的deque。

list< deque<int> >

9.3

构成迭代器范围的迭代器有何限制

[begin,end)
begin++ 能够到达end

9.4

/**
 * 编写一个函数,接受一对指向vector的迭代器和一个int值。在两个迭代器指定的范围中查找给定的值,返回一个布尔值来指出是否找到
 */

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

bool findInt(vector<int>::iterator src_begin, vector<int>::iterator src_end, int num)
{

    for (vector<int>::iterator i = src_begin; i != src_end; i++) {
        if (*i == num) return true;
    }
    return false;
}

int main(int argc, const char** argv)
{
    vector<int> a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};

    for (auto ch : a) {
        cout << ch << ",";
    }
    cout << endl;

    bool find = findInt(a.begin(), a.end(), 155);
    cout << "find 155 is " << boolalpha << find << endl;
    find = findInt(a.begin(), a.end(), 1);
    cout << "find 1 is " << boolalpha << find << endl;

    while (1) {
        ;
    }

    return 0;
}

9.5

/**
 *重写上一题的函数,返回一个迭代器指向找到的元素。注意,程序必须处理未找到给定值的情况
 */

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

vector<int>::iterator findInt(vector<int>::iterator src_begin, vector<int>::iterator src_end, int num)
{

    for (vector<int>::iterator i = src_begin; i != src_end; i++) {
        if (*i == num) return i;
    }
    return src_end;
}

int main(int argc, const char** argv)
{
    vector<int> a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};

    for (auto ch : a) {
        cout << ch << ",";
    }
    cout << endl;

    auto find = findInt(a.begin(), a.end(), 155);
    if (find == a.end()) {
        cout << "no number find" << endl;
    }
    find = findInt(a.begin(), a.end(), 1);
    if (find != a.end()) {
        cout << "find 1 is " << *find << endl;
    }
    while (1) {
        ;
    }

    return 0;
}

9.6

下面程序有何错误?你应该如何修改?

list<int> lstl;
list<int>::iterator iter1 = lstl.begin(),
                   iter2 = lstl.end();
while (iter1 < iter2)   /* ... */


迭代器是指针,对于指针比较大小没有什么意义,如果是 vector 或者 array 或者 deque 的话内存连续可以用作遍历
但是list 的地址不是连续的

9.7

 为了索引int的vector中的元素,应该使用什么类型?
 
 vector<int> sizetype    索引也就是下标
 
 #include <iostream>
#include <vector>
using namespace std;

int main(int argc, const char** argv)
{

    vector<int> a = {1, 2, 3, 4, 5, 6, 7, 8};
    cout << a.size() << endl; // 8
    while (1)
        ;
    return 0;
}

9.8

为了读取string的list的元素,应该使用什么类型?如果写入list,又该使用什么类型

写: list<string>::iterator 
读: list<string>::const_iterator    

9.9

begin和cbegin两个函数有什么不同

iterator 和 const_iterator

9.10

/* 下面的4个对象分别是什么类型 */ 
vector<int> v1;
const vector<int> v2;
auto it1 = v1.begin(), it2 = v2.begin();
auto it3 = v1.cbegin(), it4 = v2.cbegin();

it1 vector<int>::iterator
it2 vector<int>::const_iterator
it3 vector<int>::const_iterator
it4 vector<int>::const_iterator

9.11

/*
对6种创建和初始化vector对象的方法,每一种都给出一个实例。解释每个vector包含什么值
*/

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

void printVecInfo(const vector<int> src)
{
    cout << "size=" << src.size() << "   :    ";
    for (auto ch : src) cout << ch << ",";
    cout << endl;
}

int main(int argc, const char** argv)
{
    using C = vector<int>;

    C a1;
    C a2{1, 2, 3, 4, 5, 6, 7, 8, 9};
    C a3 = a2;
    C a4(a2.begin(), a2.begin() + 2);
    C a5(5);
    C a6(6, 1);

    printVecInfo(a1); // size=0   :
    printVecInfo(a2); // size=9   :    1,2,3,4,5,6,7,8,9,
    printVecInfo(a3); // size=9   :    1,2,3,4,5,6,7,8,9,
    printVecInfo(a4); // size=2   :    1,2,
    printVecInfo(a5); // size=5   :    0,0,0,0,0,
    printVecInfo(a6); // size=6   :    1,1,1,1,1,1,

    while (1) {
        ;
    }

    return 0;
}

9.12

 对于接受一个容器创建其拷贝的构造函数,和接受两个迭代器创建拷贝的构造函数,解释它们的不同
 
 答案在p300顶部
 接受一个容器创建其拷贝的构造函数,要求两个容器类型及元素类型必须匹配。
 接受两个迭代器创建拷贝的构造函数,不要求容器类型匹配,而且元素类型也可以不同,只要拷贝的元素能转换就可以
 
list<int> numbers = {1, 2, 3, 4, 5};
list<int> numbers2(numbers);        // ok, numbers2 has the same elements as numbers
vector<int> numbers3(numbers);      // error: no matching function for call...
list<double> numbers4(numbers);     // error: no matching function for call...


list<int> numbers = {1, 2, 3, 4, 5};
list<int> numbers2(numbers.begin(), numbers.end);        // ok, numbers2 has the same elements as numbers
vector<int> numbers3(numbers.begin(), --numbers.end());  // ok, numbers3 is {1, 2, 3, 4}
list<double> numbers4(++numbers.beg(), --numbers.end());        // ok, numbers4 is {2, 3, 4}
forward_list<float> numbers5(numbers.begin(), numbers.end());   // ok, number5 is {1, 2, 3, 4, 5}

9.13

/*如何用一个list<int>初始化一个vector<double>, 从一个vector<int>又该如何创建*/

#include <iostream>
#include <list>
#include <vector>
using namespace std;

int main(int argc, const char** argv)
{

    list<int> a = {1, 2, 3, 4, 5, 6, 7};
    vector<double> b(a.begin(), a.end());
    vector<int> c = {1, 2, 3, 4, 5, 6, 7};
    vector<double> d(c.begin(), c.end());

    return 0;
}

9.14

/*
编写程序,将一个list中的char*指针(指向C风格字符串)元素赋值给一个vector中的string
*/

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

int main(int argc, const char** argv)
{

    list<const char*> a(10, "hello");
    vector<string> b;
    b.assign(a.begin(), a.end());
    for (auto ch : b) cout << ch << endl;

    while (1)
        ;
}

9.15

// 编写程序,判定两个vector是否相等。
#include <iostream>
#include <vector>
using namespace std;

int main(int argc, const char** argv)
{

    vector<int> a = {1, 2, 3, 4, 5, 6};
    vector<int> b = {2, 2, 3, 4, 5, 6};

    cout << boolalpha << (a == b) << endl;
    while (1)
        ;
}

9.16

/*重写上一题的程序,比较一个list中的一个元素和一个vector中的元素。
先转换list到vector 再比较
*/


#include <iostream>
#include <list>
#include <vector>
using namespace std;

int main(int argc, const char** argv)
{

    list<int> a(5, 1);
    vector<int> b(6, 1);

    cout << boolalpha << (vector<int>(a.begin(), a.end()) == b) << endl;
    while (1)
        ;
    return 0;
}

9.17

假定c1和c2是两个容器,下面的比较操作有何限制
容器类型相同
容器元素类型相同
容器的元素支持比较运算 包括=,<

9.18

/*
编写程序,从标准输入读取string序列,存入一个deque中。编写一个循环,用迭代器打印deque中的元素
备注: 这里需要使用ctrl+z
*/

#include <deque>
#include <string>
#include <vector>

#include <iostream>
using namespace std;

int main(int argc, const char** argv)
{

    string tmp;
    deque<string> put;
    while (cin >> tmp) {
        put.push_back(tmp);
    }
    cout << "you input :
";

    for (auto ch = put.begin(); ch != put.end(); ch++) {
        cout << *ch << endl;
    }

    while (1) {
        /* code */
    }

    return 0;
}

9.19

重写上题程序,用list代替deque。列出程序要做出哪些改变。
将deque改为list类型 iterator的类型也改为list即可。

9.20

/*
从一个list拷贝元素到两个deque中。值为偶数的所有元素都拷贝到一个deque中,而奇数值元素都拷贝到另一个deque中
*/
#include <deque>
#include <iostream>
#include <list>
#include <string>
#include <vector>
using std::cin;
using std::cout;
using std::deque;
using std::endl;
using std::list;
using std::string;
using std::vector;
// 大佬的代码
// int main()
// {
//     list<int> l{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
//     deque<int> odd, even;
//     for (auto i : l) (i & 0x1 ? odd : even).push_back(i);

//     for (auto i : odd) cout << i << " ";
//     cout << endl;
//     for (auto i : even) cout << i << " ";
//     cout << endl;

//     return 0;
// }

int main()
{
    list<int> src;
    deque<int> dst1;
    deque<int> dst2;

    int num;
    while (cin >> num) src.push_back(num);
    for (int num : src) {
        if (num & 0x01)
            dst1.push_back(num);
        else
            dst2.push_back(num);
    }

    cout << "one" << endl;
    for (int num : dst1) {
        cout << num << " ";
    }
    cout << endl;
    cout << "two" << endl;
    for (int num : dst2) cout << num << " ";

    cout << endl;
    while (1)
        ;
    return 0;
}

9.21

/* 如果我们将308页中使用insert返回值将元素添加到list中的循环程序改写为将元素插入到vector中,分析循环将如何工作

    list<string> lst;
    auto iter =lst.begin();
    while(cin>>word)
        iter=lst.insert(iter,word)
*/
一直往头部插入,vector 会执行拷贝移动

9.22

/*
假定iv是一个int的vector,下面的程序存在什么错误?你将如何修改?

vector<int>::iterator iter = iv.begin(), mid = iv.begin() + iv.size()/2;

while(iter != mid) {
    if (*iter == some_val) {
        iv.insert(iter, 2 * some_val);
    }
}

1. iter 是iv 的迭代器,插入后长度变了,mid也就失效了 同时当vector扩大时,地址全部失效了
2. 死循环,iter没有++

insertDoubleValue2 是我写的,,这里取巧了,因为end是一直变的,我们根据end-cursor就好了
*/

#include <iostream>
#include <vector>
using std::vector;

void insertDoubleValue(vector<int>& iv, int some_val)
{
    auto cursor = iv.size() / 2;
    auto iter = iv.begin(), mid = iv.begin() + cursor;
    while (iter != mid) {
        if (*iter == some_val) {
            iter = iv.insert(iter, 2 * some_val);
            ++iter;
            ++cursor;
            mid = iv.begin() + cursor;
        }
        ++iter;
    }
}

void insertDoubleValue2(vector<int>& iv, int some_val)
{
    auto cursor = iv.size() / 2;
    auto iter = iv.begin();
    while (iter != iv.end() - cursor) {
        if (*iter == some_val) {
            iter = iv.insert(iter, 2 * some_val);
            ++iter;
        }
        ++iter;
    }
}

void print(const vector<int>& iv)
{
    for (auto i : iv) std::cout << i << " ";
    std::cout << std::endl;
}

int main()
{
    vector<int> iv = {1, 1, 1, 1, 1, 7, 1, 9, 8};
    insertDoubleValue(iv, 1);
    print(iv);

    iv = {1, 1, 1, 1, 1, 7, 1, 9, 8};
    insertDoubleValue2(iv, 1);
    print(iv);
    while (1)
        ;
}

9.23

在本节第一个程序(309页)中,若c.size()为1, 则val, val2, val3和val4的值会是什么
    第一个元素

9.24

编写程序,分别使用at、下标运算符、front和begin提取一个vector中的第一个元素。
    在一个空vector上测试你的程序
    
    
#include <iostream>
#include <vector>
using namespace std;

int main(int argc, const char** argv)
{

    std::vector<int> v;
    std::cout << v.at(0);    // terminating with uncaught exception of type std::out_of_range
    std::cout << v[0];       // Segmentation fault: 11
    std::cout << v.front();  // Segmentation fault: 11
    std::cout << *v.begin(); // Segmentation fault: 11

    while (1) return 0;
}

9.25

对于312页中删除一个范围内的元素的程序,如果elem1与elem2相等会发生什么?


如果elem2是尾后迭代器,或者elem1和elem2皆为尾后迭代器,又会发生什么
elem1=slist.erase(elements,elem2)

1. 不删除元素,不发生改变
2. 清空元素
3. 不删元素,不发生改变

9.26

/*
使用下面代码定义的ia,将ia拷贝到一个从vector和一个list中。
使用单迭代器版本的erase从list中删除奇数元素,从vector中删除偶数元素。
*/
#include <iostream>
#include <list>
#include <vector>
using namespace std;

int main(int argc, const char** argv)
{
    int ia[] = {0, 1, 1, 2, 3, 5, 8, 13, 21, 55, 89};

    // 这么做也可以,说明迭代器是+1的计算方式
    // vector<int> va(ia, ia + sizeof(ia) / sizeof(int));
    vector<int> va(begin(ia), end(ia));

    list<int> lb(va.begin(), va.end());

    for (auto it = va.begin(); it != va.end();) {
        if ((*it) % 2)
            it = va.erase(it);
        else
            it++;
    }

    for (auto it = lb.begin(); it != lb.end();) {
        if ((*it) % 2)
            it++;
        else
            it = lb.erase(it);
    }

    for (auto ch : va) cout << ch << ",";
    cout << endl;
    for (auto ch : lb) cout << ch << ",";
    cout << endl;

    while (1)
        ;
    return 0;
}

9.27

/*
编写程序,查找并删除forward_list中的奇数元素。
*/
#include <forward_list>
#include <iostream>
using namespace std;
int main(int argc, const char** argv)
{

    forward_list<int> flst = {2, 1, 2, 3, 4, 5, 6, 7, 8, 9};

    auto prev = flst.before_begin();
    auto curr = flst.begin();

    while (curr != flst.end()) {
        if (*curr % 2) {
            curr = flst.erase_after(prev);
        }
        else {
            prev = curr;
            curr++;
        }
    }

    for (auto ch : flst) cout << ch << ",";

    while (1)
        ;
    return 0;
}

9.28

/*
编写函数,接受一个forward_list和两个string共三个参数。
函数应在链表中查找第一个string,并将第二个string插入到紧接着第一个string之后的位置。
若第一个string未在链表中,则将第二个string插入到链表末尾。
*/

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

void insert_lst(forward_list<string>& src, string after, string what)
{
    if (src.empty()) {
        return;
    }

    auto prev = src.before_begin();
    auto curr = src.begin();

    while (curr != src.end()) {
        if (*curr == after) {
            src.insert_after(curr, what);
            return;
        }
        else {
            curr++;
            prev++;
        }
    }
    src.insert_after(prev, what);
}

int main(int argc, const char** argv)
{

    forward_list<string> lst = {"www", ".baidu", ".com"};

    insert_lst(lst, ".baidu", ".hello");
    for (auto ch : lst) cout << ch << endl;
    insert_lst(lst, "xxx", ".hello");
    for (auto ch : lst) cout << ch << endl;
    while (1)
        ;
    return 0;
}

9.29

假定vec包含25个元素,那么vec.resize(100)会做什么?如果接下来调用vec.resize(10)会做什么
    1. 尾部添加75个0,同时可能因为移动拷贝,迭代器失效
    2. 丢弃尾巴的90个元素

9.30

接受单个参数的resize版本对元素类型有什么限制

如果是类的话,需要有默认构造函数,或者初始值

9.31

// 大佬使用了  advance(prv, 2) 来操作迭代器

/*第316页中删除偶数值元素并复制奇数值元素的程序不能用于list或forward_list。
修改程序,使之也能用于这些类型
*/
#include <forward_list>
#include <iostream>
#include <list>
#include <vector>
using namespace std;

template <typename T> 
void print(T src)
{
    for (auto ch : src) 
        cout << ch <<",";
    cout<<endl;
}

int main(int argc, const char** argv)
{
    vector<int> v1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    list<int> l1(v1.begin(),v1.end());
    forward_list<int> l2(v1.begin(),v1.end());


    // 删除偶数元素,复制每个奇数元素
    auto it1 = v1.begin();
    while (it1 != v1.end()) {
        if (*it1 % 2) {
            it1 = v1.insert(it1, *it1);
            it1+=2;
        }
        else {
            it1=v1.erase(it1);
        }
    }
    print(v1);


    {   // list 使用两个++
        // 删除偶数元素,复制每个奇数元素
        auto it1 = l1.begin();
        while (it1 != l1.end()) {
            if (*it1 % 2) {
                it1 = l1.insert(it1, *it1);
                it1++;
                it1++;

            }
            else {
                it1=l1.erase(it1);
            }
        }
        print(l1);
    }


    {   // forward_list 只有insert_after
        // 删除偶数元素,复制每个奇数元素
        auto curr = l2.begin();
        auto prev=l2.before_begin();
        while (curr != l2.end()) {
            if (*curr % 2) {
                prev = l2.insert_after(prev,*curr); 
                prev++;         // 指向了原来的curr
                //curr=prev;    // 可以注释掉,这里不会发生迭代器失效
                curr++;
            }
            else {
                curr=l2.erase_after(prev);
            }
        }
        print(l2);
    }

    while (1);

    return 0;
}

9.32


316页的程序中,向下面语句这样调用insert是否合法?如果不合法,为什么?
iter = vi.insert(iter, *iter++);

*从右到左
iter++ 从左到右.++ 操作的是iter
*iter++ 根据优先级 *iter  然后iter++
https://stackoverflow.com/questions/2934904/order-of-evaluation-in-c-function-parameters


无法确认是先执行  *iter++ 还是先 insert  
或者返回后 先赋值给iter  还是先iter++,再返回给iter

9.33

在本节最后一个例子中,如果不将insert的结果赋予begin,将会发生什么?
编写程序,去掉此赋值语句,验证你的答案。

#include "include.h"


int main(int argc, const char** argv) {
 
    vector<int> ivec = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    auto iter = ivec.begin();
    while (iter != ivec.end()) {
        ++ iter;
        /* iter = */ivec.insert(iter, 42);
        // 调试可以发现 刚开始 iter=2
        // 执行玩insert后=0 失效了
        ++ iter;
    }

    print(ivec);

    while(1);
    return 0;

9.34

死循环

/*假定vi是一个保存int的容器,其中有偶数值也要奇数值,分析下面循环的行为,然后编写程序验证你的分析是否正确。*/



#include "include.h"

int main(int argc, const char** argv) {
 
    vector<int> v1={1,2,3,4,5,6,7,8,9};

    auto iter=v1.begin();
    while(iter!=v1.end())
    {
        if(*iter%2)
        {
            iter=v1.insert(iter,*iter);
            // ++iter;  ///-----if里面也需要++一次
        }
        ++iter;
    }
    print(v1);
    while(1);
    return 0;
}

9.35

解释一个vector的capacity和size有何区别
capacity 表示不用重新分配内存时占用的内存大小
size 表示已经存储的元素的大小

9.36

一个容器的capacity可能小于它的size吗
不会
capacity >= size

9.37

为什么list或array没有capacity成员函数?

list 是链表,插入的时候分配内存
array 是固定大小的

9.38

/**
    编写程序,探究在你的标准库实现中,vector是如何增长的
 */

#include "include.h"


void printInfo(vector<int> &v)
{
    cout <<"size="<<v.size()<<endl;
    cout <<"capacity="<<v.capacity()<<endl;
}

int main(int argc, const char** argv) {
 
    vector<int> v1;
    printInfo(v1);      //size=0,capacity=0

    v1.push_back(1);    //size=1,capacity=1
    printInfo(v1);      

    v1.push_back(1);    //size=2,capacity=2
    printInfo(v1);

    v1.push_back(1);    //size=3,capacity=4
    printInfo(v1);


    while(1);
    return 0;
}

9.39

vector<string> svec;
svec.reserve(1024);
string word;
while (cin >> word) {
    svec.push_back(word);
}
svec.resize(svec.size() + svec.size()/2);

1. 分配容量为1024的容器,如果超了的话再分配
2. 填充后1/4 为空串  最后使用resize只能改变vector的size,不能改变其capacity

9.40

如果上一题的程序读入了256个词,在resize之后容器的capacity可能是多少?
如果读入了512个、1000个或1048个词呢?


256---256+256/2=384-------1024
512---512+512/2=768-------1024
1000--1000+1000/2=1500----这个可能是2048,但实际是//size=1500 capacity=2000
1048--1024*2=1536---------2048吧 

// 可以看出来 直接  resize 出来的 capacity= resize*2-----这里可能编译器做法不一样的
// 直接push一个个的是+1
    
    
    
#include "include.h"

template<typename T>
void printInfo(const T& v)
{
    cout <<"size="<<v.size()<<endl;
    cout <<"capacity="<<v.capacity()<<endl;
}


int main(int argc, const char** argv) {

    vector<string> svec;
    svec.reserve(1024);
    string word;

    for(int i=0;i<1000;i++){
        svec.push_back("123");
    }
    svec.resize(svec.size() + svec.size()/2);
    printInfo(svec);//size=1500 capacity=2000----------------------------


    vector<string> svec2;
    svec2.reserve(1024);
    for(int i=0;i<1500;i++){
        svec2.push_back("123");
    }
    printInfo(svec2);//size=1500 capacity=2048--------------------------
 
    while(1);
    return 0;
}

9.41

/*
    从vector<char> 创建 string
*/
#include "include.h"


int main(int argc, char const *argv[])
{
    vector<char> vstr={'1','2','3',''};

    string s(vstr.begin(),vstr.end());
    cout<<s<<endl;
    while(1);
    return 0;
}

9.42

假定你希望每次读取一个字符存入一个string中,而且知道最少需要读取100个字符,应该如何提高性能

使用reserve提前分配好空间,来确保 capacity 大于100

9.43

9.44

/*
编写一个函数,接受三个string参数s,oldVal和newVal.使用迭代器及insert和erase函数将s中所有oldVal替换为newVal。测试你的程序,用它替换通用的简写形式,如,将“tho”替换为“though”,将“thru”替换为“through”。

replaceString   迭代器
replaceString0  下标+replace
*/

#include "include.h"



// 使用了下标,和replace
void replaceString0(string& s,string& sold, string& snew)
{
    size_t sold_size=sold.size();
    for(size_t i=0;i+sold_size<s.size();i++)
    {
        if(s.substr(i,sold_size)==sold)
        {
            s.replace(i,sold_size,snew);
            i+=snew.size();
        }
    }
}


// 使用了下标,不符合题目
void replaceString1(string& s,string& sold, string& snew)
{
    size_t sold_size=sold.size();
    for(size_t i=0;i+sold_size<s.size();i++)
    {
        if(s.substr(i,sold_size)==sold)
        {
            s.erase(i,sold_size);
            s.insert(i,snew);
            i+=snew.size();
        }
    }
}
// 使用迭代器 转换了下标
void replaceString2(string& s,string& sold, string& snew)
{
    size_t sold_size=sold.size();
    for(auto beg=s.begin(); distance(beg,s.end()) >=distance(sold.begin(),sold.end());beg++)
    {
        if(s.substr(beg-s.begin(),sold_size)==sold)
        {
            s.erase(beg-s.begin(),sold_size);
            s.insert(beg-s.begin(),snew);
            advance(beg,snew.size());
        }
    }
}


// 完全使用迭代器
void replaceString(string& s,string& sold, string& snew)
{
    size_t sold_size=sold.size();
    for(auto beg=s.begin(); distance(beg,s.end()) >=distance(sold.begin(),sold.end());beg++)
    {
        // if(s.substr(beg-s.begin(),sold_size)==sold)
        if(string(beg,beg+sold.size())==sold) 
        {
            beg=s.erase(beg,beg+sold_size);
            beg=s.insert(beg,snew.begin(),snew.end());
            advance(beg,snew.size());
        }
    }
}

int main(int argc, char const *argv[])
{
    {
        string s="123 456 789 ";
        string sold="456";
        string snew="AAAA";
        replaceString(s,sold,snew);
        cout << s <<endl;
    }



     {
        string s="123 456 789 ";
        string sold="456";
        string snew="AAAA";
        replaceString0(s,sold,snew);
        cout << s <<endl;
    }
   
    while(1);


    return 0;
}

9.45

9.46

/*
9.45
接受一个表示名字的string参数和两个分别表示前缀(如“Mr."或”Ms.“)和后缀(Jr或III)的字符串。使用迭代器及insert和append函数将前缀和后缀加到给定的名字中,将生成的新string返回。

9.46
重写上一题的函数,这次使用位置和长度来管理string,并只使用insert
 */

#include "include.h"


string fullName(const string& s,const string& before,const string& after)
{
    string full(s);
    full.insert(full.begin(),before.begin(),before.end());
    full.append(after);
    return full;
}


string fullName2(const string& s,const string& before,const string& after)
{
    string full(s);
    full.insert(0,before);
    full.insert(full.size(),after);
    return full;
}




int main(int argc, char const *argv[])
{

    cout << fullName("layty","Mr."," good")<<endl;
    cout << fullName2("layty","Mr."," good")<<endl;

    while(1);
    return 0;
}

9.47


/*
编写程序,首先查找string "ab2c3d7R4E6"中的每个数字字符,然后查找其中每个字母字符。编写两个版本的程序,第一个要使用find_fisrt_of,第二个要使用 find_first_not_of
*/
#include "include.h"
void find1(const string& s)
{
    string number("0123456789");
    string abc;
    for(int i=0;i<26;i++)
    {
        abc.push_back('a'+i);
        abc.push_back('A'+i);
    }

    string::size_type pos=0;
    while( (pos=s.find_first_of(number,pos)) != string::npos)
    {
        cout << s[pos]<<endl;
        pos++;        
    }

    pos=0;
    while( (pos=s.find_first_of(abc,pos)) != string::npos)
    {
        cout << s[pos]<<endl;
        pos++;        
    }

    //----------------------------------------------------------
    pos=0;
    while( (pos=s.find_first_not_of(number,pos)) != string::npos)
    {
        cout << s[pos]<<endl;
        pos++;        
    }

    pos=0;
    while( (pos=s.find_first_not_of(abc,pos)) != string::npos)
    {
        cout << s[pos]<<endl;
        pos++;        
    }


}




int main(int argc, char const *argv[])
{
    find1("123ABC456");
    while(1);
    return 0;
}

9.48

假定name和numbers的定义如325页所示,number.find(name)返回什么?

string name = "AnnaBelle";
string number = "0123456789";
auto result = number.find(name);
if (result == string::npos) {
    cout << "npos" << endl;
}

返回 string::npos

9.49

/*
如果一个字母延伸要中线之上,如d或f,则称其有上出头部分。如果延伸到中线之下,则称其有下出头部分。编写程序,读入一个单词文件,输出最长的既不包含上出头部分,也不包含下出头部分的单词。
*/
#include <fstream>
#include "include.h"

int main(int argc, char const *argv[])
{
    ifstream file("E:ReadingC++C+++PrimerCppPrimer-masterCppPrimer-masterch09ex9_49.cpp");
    if(!file) 
    {
        cout << "file open filed"<<endl;
        while(1);
        return -1;
    }

    string s;
    string get;
    while(file>>s)
    {
        if(s.find_first_not_of("aceimnorsuvwxz")==string::npos)
        {
            if(get.size()<s.size())
                get=s;
        }
    }
    cout << "get: "<<get <<endl;

    while(1);
    return 0;
}

9.50

/*
编写程序处理一个vector,其元素都表示整形值。计算vector中所有元素之和。修改程序,使之计算表示浮点值的string之和
*/

#include "include.h"
int sum_int(const vector<string>& s)
{
    int  n=0;
    for(auto ch : s)
    {   
        if(ch.find_first_of("0123456789")!=string::npos)
            if(ch.substr(ch.find_first_of("+-.0123456789")).size())
            {
                n+=stoi(ch);
            }

    }
    return n;
}

double sum_double(const vector<string>& s)
{
    double  n=0;
    for(auto ch : s)
    {   
        if(ch.find_first_of("0123456789")!=string::npos)
            if(ch.substr(ch.find_first_of("+-.0123456789")).size())
            {
                n+=stod(ch);
            }

    }
    return n;
}


int main(int argc, char const *argv[])
{
    vector<string> s={"---","2.1","2.1","-3"};
    cout << "sum="<<sum_int(s)<<endl;
    cout << "sum="<<sum_double(s)<<endl;
    while(1);
    return 0;
}

9.51

/*
设计一个类,它有三个unsigned成员,分别表示年、月和日。为其编写构造函数,接受一个表示日期的string参数。你的构造函数应该能处理不同数据格式,如January 1,1900、1/1/1990、Jan 1 1900等。
*/
#include "include.h"
#include <array>


class mydate
{
private:
    /* data */
    unsigned int year=1990;
    unsigned int month=1;
    unsigned int day=1;
public:
    mydate(const string& s);
    ~mydate();
};

mydate::mydate(const string& s1="")
{
    string s(s1);
    if(s.empty()) return;

    string::size_type pos;
    string::size_type year_pos,month_pos;
    string::size_type pos_day,pos_month,pos_year;
    if((pos=s.find("/"))!= string::npos) // 1/1/1990
    {
        // day
        s=s.substr(s.find_first_of("0123456789"));
        day=stoul(s,&pos_day);
        // month
        s=s.substr(s.find_first_of("0123456789",pos_day));
        month=stoul(s,&pos_month);
        // year
        s=s.substr(s.find_first_of("0123456789",pos_month));
        year=stoul(s);

    } 
    else    //Jan 1 1900
    {
        std::array<std::string, 12> month_names{"Jan", "Feb", "Mar", "Apr", "May", "Jun","Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
        for(int i=0;i<12;i++)
        {
            if(s.find(month_names[i])!=string::npos)
            {
                 month=i+1;
                 break;
            }   
        }
        // day
        s=s.substr(s.find_first_of("0123456789"));
        day=stoul(s,&pos_day);
        // year
        s=s.substr(s.find_first_of("0123456789",pos_day));
        year=stoul(s);


        
    }
    
    cout<< "year="<<year<<" month="<<month<<" day="<<day<<endl;
}

mydate::~mydate()
{
}




int main(int argc, char const *argv[])
{
    mydate("3/4/2021");
    mydate("Dec 2 2022");
    mydate("January 1,2023");
    
    while(1);
    return 0;
}

9.52

#include "include.h"

#include <stack>


int main(int argc, char const *argv[])
{

    // 1*(2+10)-11

    stack<string> s;


    string  abc="1*(2+10)-1";


    string num;
    string::size_type i=0;
    for(auto ch : abc)
    {
        i++;

        if(ch>='0' && ch <='9')
        {
            num.append(string(1,ch));
            if(i==abc.size())
            {
                s.push(num);
            }
        }
        else
        {
            if(!num.empty())
            {
                s.push(num);
            }
            s.push(string(1,ch));
            num.erase();
        }
    }
    while(!s.empty())
    {
        cout<<s.top()<<endl;
        s.pop();
    }



    auto& expr = "This is (Mooophy(awesome)((((wooooooooo))))) and (ocxs) over";

    stack<char> s1;

    int ok=0;

    for(auto ch: expr)
    {
        s1.push(ch);
        if(ch=='(')  ok++;
        if(ch==')' && ok)
        {
            while(s1.top()!='(')
            {
                s1.pop();
            }
            s1.pop();
            s1.push('#');
            ok--;
        }
    }

    string output;
    for (; !s1.empty(); s1.pop()) output.insert(output.begin(), s1.top());
    cout << output << endl; // "This is # and # over"







    while(1);
    return 0;
}

以上是关于cppPrimer学习-9th的主要内容,如果未能解决你的问题,请参考以下文章

cppPrimer学习12th

cppPrimer学习11th

cppPrimer学习8th

c_cpp 审查CppPrimer#104

[Operating.System.Concepts(9th,2012.12)].Abraham.Silberschatz.文字版(恐龙书——操作系统概念 原书第九版)课后习题 参考答案

JVM Specification 9th Edition Cover