本文答案,部分参考于C++ Primer 习题集
前面章节的习题答案
配套的学习资料
https://www.jianguoyun.com/p/DTK5uJgQldv8CBjKv80D
17.1
tuple<int,int,int> ti{10,20,30};
17.2
tuple<string, vector<string>, pair<string, int>> t;
17.3
17.4
/*
* This file contains code from "C++ Primer, Fifth Edition", by Stanley B.
* Lippman, Josee Lajoie, and Barbara E. Moo, and is covered under the
* copyright and warranty notices given in that book:
*
* "Copyright (c) 2013 by Objectwrite, Inc., Josee Lajoie, and Barbara E. Moo."
*
*
* "The authors and publisher have taken care in the preparation of this book,
* but make no expressed or implied warranty of any kind and assume no
* responsibility for errors or omissions. No liability is assumed for
* incidental or consequential damages in connection with or arising out of the
* use of the information or programs contained herein."
*
* Permission is granted for this code to be used for educational purposes in
* association with the book, given proper citation if and when posted or
* reproduced.Any commercial use of this code requires the explicit written
* permission of the publisher, Addison-Wesley Professional, a division of
* Pearson Education, Inc. Send your request for permission, stating clearly
* what code you would like to use, and in what specific way, to the following
* address:
*
* Pearson Education, Inc.
* Rights and Permissions Department
* One Lake Street
* Upper Saddle River, NJ 07458
* Fax: (201) 236-3290
*/
#include <cassert>
#include <utility>
using std::pair;
#include <string>
using std::string;
#include <tuple>
using std::tuple; using std::get;
using std::make_tuple;
#include <vector>
using std::vector;
#include <numeric>
using std::accumulate;
#include <algorithm>
using std::equal_range;
#include <exception>
#include <stdexcept>
using std::domain_error;
#include <iostream>
using std::ostream; using std::istream;
using std::cout; using std::endl;
#include <fstream>
using std::ifstream;
#include "Sales_data.h"
bool lt(const Sales_data &lhs, const Sales_data &rhs)
{
return lhs.isbn() < rhs.isbn();
}
// need to leave this for as a traditional for loop because we
// use the iterator to compute an index
// matches has three members: an index of a store and iterators into that store's vector
typedef tuple<vector<Sales_data>::size_type,
vector<Sales_data>::const_iterator,
vector<Sales_data>::const_iterator> matches;
// files holds the transactions for every store
// findBook returns a vector with an entry for each store that sold the given book
vector<matches>
findBook(const vector<vector<Sales_data>> &files,
const string &book)
{
vector<matches> ret; // initially empty
// for each store find the range of matching books, if any
for (auto it = files.cbegin(); it != files.cend(); ++it) {
// find the range of Sales_data that have the same ISBN
auto found = equal_range(it->cbegin(), it->cend(),
book, compareIsbn);
if (found.first != found.second) // this store had sales
// remember the index of this store and the matching range
ret.push_back(make_tuple(it - files.cbegin(),
found.first, found.second));
}
return ret; // empty if no matches found
}
vector<Sales_data> build_store(const string &s)
{
Sales_data item;
vector<Sales_data> ret;
ifstream is(s);
while (read(is, item))
ret.push_back(item);
sort (ret.begin(), ret.end(), lt); // need sort for equal_range to work
return ret;
}
void reportResults(istream &in, ostream &os,
const vector<vector<Sales_data>> &files)
{
string s; // book to look for
while (in >> s) {
auto trans = findBook(files, s); // stores that sold this book
if (trans.empty()) {
cout << s << " not found in any stores" << endl;
continue; // get the next book to look for
}
for (const auto &store : trans) // for every store with a sale
// get<n> returns the specified member from the tuple in store
os << "store " << get<0>(store) << " sales: "
<< accumulate(get<1>(store), get<2>(store),
Sales_data(s))
<< endl;
}
}
int main(int argc, char **argv)
{
assert(argc > 1);
// each element in files holds the transactions for a particular store
vector<vector<Sales_data>> files;
for (int cnt = 1; cnt != argc; ++cnt)
files.push_back(build_store(argv[cnt]));
ifstream in("../data/findbook.in"); // ISBNs to search for
reportResults(in, cout, files);
}
17.5
1.matches的类型改为pair,其中第二个成员还是一个pair,保存节目的起止迭代器.
2.findBook中构造返回值的部分,用make_pair构造一个pair,第一个参数与tuple版本一样,第二个参数直接用found
3.reportResult从findBook返回的matches中提取数据,进行输出的部分,get<0>(store),get<1>(store)和get<2>(store)改为store,first.store,second.first.和store.second.second
typedef pair<vector<Sales_date>::size_type,pair<vector<Sales_data>::const_iterator,vector<Sales_date>::const_iterator>> matches;
ret.push_back(make_pair(it-files.cbegin(),found));
os<<"sotre "<<sotre.first<<" sales: "<<accdumulate(sotre.second.first,storer.second.second,Sales_data(s))
<<endl;
17.6
17.7
本题只是简单使用搜索结果,pair和tuple都是简单直接的实现方式.
如果搜索结果还需进行复杂的计算,处理,定义一个类对其进行封装会更好.
17.8
Sales_data()是Sales_data的默认构造函数,对所有数据成员都采用值初始化,因此lsbn被初始化为空字符串.因此,再输出结果中,见看不到数目的isbn()
17.9
(a)bitvec为32位,第五位位1,剩余位位0
(b)bv位32位,0,2,4,6这4位位1,剩余位位0
© bv为8位.用bstr来对其初始化,若读入的字符串不是单纯的二进制字符串.程序会抛出invalid_argument异常.
17.10
#include<iostream>
#include<bitset>
using namespace std;
int main() {
unsigned bp = 2 | (11 < 2) | (1 << 5) | (1 << 8) | (1 << 13) | (1 << 21);
bitset<32> bv(bp);
cout << bv << endl;
bitset<32> bv1;
bv1.set(1); bv1.set(2); bv1.set(3); bv1.set(5);
bv1.set(8); bv1.set(13); bv1.set(21);
cout << bv1 << endl;
return 0;
}
输出结果如下:
00000000001000000010000100100010
00000000001000000010000100101110
17.11
如果使用整数来保存测验解答,那么对于10个问题的测验,只需一个短整形对象即可.如果改为100道题,则需要4个32位整数或是2个64位整数.而且修改的并不仅仅是数据结果,所有对整形数进行操作来修改解答和评分的代码都要相应修改,工作量很大.
采用bitset则有很明显的优势,当题目数改变时,我们只需改变bitset的规模,而操作bitset来完成答案,评分的代码则只需进行很小的修改.
最佳的方式是定义一个类模板,它有一个模板参数表示题目数.有一个bitset成员保存解答.然后定义一些成员函数来完成改答案,评分等操作,当题目数发生变化,我们只需实例化一个新版本.其他代码均无法改动.
17.12
此函数直接调用bitset的set操作即可,程序见下题.
17.13
17.14
regex r("[[:alnum]]+\\.(cpp|cxx|cc)$",regex::icase);
17.15
17.16
若pattern只是
" [^c]ei ",则只与" ?ei "形式的字符串匹配.其中?是除c之外的知乎,因此,输出的只是错误拼写的部分,而不是包含错误拼写的完整单词,例如:对" friend"只输出" rie".
17.17
17.18
在使用匹配时(在本题中,即for循环中输出匹配字符串)排除例外情况即可.
if(it->str()!="albeit"&&it->str()!="neighbor")
cout<<it->str()<<endl;
17.19
当子匹配未匹配时,其str()会返回空string,仍然可以合法使用
17.20
17.21
17.22
首先,将正则表达式改为:
"(\\()?(\\d{3})(\\)?([-.])(\\s)*)?(\\d{3}([-.](\\s)*)?(\\d{4}))"
表示间隔三部分的可以是一个".",一个“-”,或是多个空白符(\s).
然后要修改valid的判断逻辑
1 若有开始左括号,则第三个子匹配必须也匹配(有配对右括号),且第4个子匹配不能是分隔符,必须是空白符或是没有.
2 若无开始左括号,则也不能右右括号,且4,6两个子匹配必须一样------------同为".",或同为“-”,或同为空白序列(都不是".",“-”)
-----------------占位符-------------
17.23
"(\\d{5})((-?)(\\d{4}))?"
17.24
略
17.25
利用regex迭代器,只取第一个匹配即可.另一种方式是保存所有匹配的号码,但在输出时,只输出第一个号码.
17.26
sregex_iterator it(line.begin(),line.end(),r),end_it;
for(it++;it!=end_it;it++)
if(valid(*it))
info.phones.push_back("V"+it->str());
else info.phones.push_back("I"+it->str());
17.27
#include<iostream>
#include<string>
#include<regex>
using namespace std;
int main() {
string zip = "(\\d{5})(-?)(\\d{4}))?";
regex r(zip);
string s;
string fmt = "$1-$2";
while (getline(cin, s)) {
for (sregex_iterator it(s.begin(), s.end(), r), end_it; it != end_it; += it) {
if ((*it)[2].matched && (*it)[2].str()[0] != '-')
cout << (*it).format(fmt) << endl;
else
cout << (*it).str() << endl;
}
}
return 0;
}
17.28
17.29
17.30
17.31
在循环内定义b和e,每个循环步都会用到默认的种子(0)重新初始化随机数引擎e,因此,调用b(e)永远得到的是特定随机数的第一个数,游戏的先行者永远是固定的.
而在循环外定义,则可保持引擎的状态.每次得到随机数序列中的下一个值.游戏的先行者会改变.
17.32
如果在循环内定义resp,则其生命周期仅在循环体内,而while循环条件判定不属于循环体.因此,在进行循环体条件判定时,resp已经被销毁,程序会产生编译错误.
17.33
17.34
17.35
用hexfloat指定浮点数并打印成16进制.用uppercase指定打印大写形式,
cout<<"hexadecimal: "<<hexfloat<<uppercase<<sqrt(2.0)<<'\n';
17.36
17.37
17.38
修改循环内逻辑,读取并打印文本后,并不打印换行.而是在判断未出现fail状态.也就是说,getline读取成功且未达到上限时才打印回车.这样就可以很多次读入的一行文本仍然打印成一行.
cout<<text;
if(!in.good())
if(in.gcount()==29)
in.clear();
else
break;
else cout<<endl;
17.39
参考书中本节内容实现即可
有一点需要注意,如果是在Windows平台使用gcc编译器,编译此程序,得到的目标程序在处理Winoows格式的文本文件(每行结尾是两个之路,CR-回车.LF-换行)时会产生seek定位不准的情况.处理UNIX格式的文件(行尾只有一个LF)则没有问题,用VC编译得到的目标程序则是相反的情况.