C++Primer-课后习题第十七章

本文答案,部分参考于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编译得到的目标程序则是相反的情况.

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值