C++程序设计原理与实践 习题答案 第二十五章 第25章习题答案

本章习题所用到的头文件和实现

Pool.h

实现了两个版本的Pool,一个用标记数组跟踪已分配和未分配对象空间,另一个用链表跟踪

#include <list>

using namespace std;

//v1 Pool,用数组和索引跟踪已分配和未分配对象,
//分配速度如果是顺序分配则较快,若随机分配则有些慢
//释放速度快,额外空间占用小
template<typename T, int N>
class Pool_v1
{
	size_t sz;			//存储池总数量
	size_t un_alloc;	//未分配的对象的数量
	size_t luai;		//内存地址最小的未分配的对象的索引 least unallocated index
	T* space;			//内存空间,N个T对象
	bool is_alloc[N];	//表明哪个已分配,哪个未分配
	
public:
	Pool_v1();					//创建N个T的存储池
	T* get();				//从存储池获取一个T,若无空闲T则返回0
	void free(T*);			//将get()获得的一个T归还存储池
	int available() const	//空闲T的数目
	{
		return un_alloc;
	}
};

template<typename T, int N>
Pool_v1<T,N>::Pool_v1()
	:sz{ N }, un_alloc{ N }, luai{ 0 }, space{ new T[N] }
{
	for (size_t i = 0; i < N; ++i)
		is_alloc[i] = false;
}

template<typename T, int N>
T* Pool_v1<T, N>::get()
{
	if (un_alloc == 0)
		return 0;
	//先确定要返回的对象地址
	size_t index = luai;
	is_alloc[index] = true;
	--un_alloc;
	//下面寻找下一个未分配的对象
	if (un_alloc == 0)
		luai = sz;		//如果都分配满了,那么就把它设置为最后的索引之后的位置
	else
		for (size_t i = luai + 1; i < sz; ++i)
			if (!is_alloc[i])
			{
				luai = i;
				break;
			}
	return &space[index];
}

template<typename T, int N>
void Pool_v1<T, N>::free(T* obj)
{
	*obj = T{};		//将归还的对象设置为默认值
	++un_alloc;
	size_t index = obj - space;	//释放位置的索引
	if (index < luai)
		luai = index;
	is_alloc[index] = false;
}

//------------------------------------------------------------------



//v2 Pool,用链表跟踪已分配和未分配对象,
//分配速度若顺序分配慢于Pool_v1,随机分配可能会快一些,
//释放速度慢,且额外空间占用大

//需要一个专用于Pool的list,其insert和erase操作不进行动态内存分配和释放
template<typename T>
struct Node
{
	T val;
	Node* pred;
	Node* succ;
};

template<typename T>
class List_for_pool
{
	Node<T>* header;
	size_t sz;
public:
	class iterator;

	List_for_pool();
	~List_for_pool();

	iterator begin() { return iterator{ header->succ }; }
	iterator end() { return iterator{ header }; }

	//以下的加入和移除元素,都不释放节点
	iterator insert(iterator p, Node<T>* pn);	//将节点 n 插入链表中 p 之后的位置
	iterator erase(iterator p);					//从链表中删除p

	//以下加入和删除元素,会动态分配内存
	void push_back(const T& v);

	size_t size() const { return sz; }
};

template<typename T>
class List_for_pool<T>::iterator
{
	Node<T>* curr;
public:
	iterator(Node<T>* p) :curr{ p } { }

	iterator& operator++() { curr = curr->succ; return *this; }
	T& operator*() { return curr->val; }

	bool operator==(const iterator& b) const { return curr == b.curr; }
	bool operator!=(const iterator& b) const { return curr != b.curr; }

	Node<T>* get_pnode() { return curr; }	//用于直接获得节点指针
};

template <typename T>
List_for_pool<T>::List_for_pool()
	:header{ new Node<T>{T{},nullptr,nullptr} }, sz{ 0 }
{
	header->succ = header->pred = header;
}

template <typename T>
List_for_pool<T>::~List_for_pool()
{
	Node<T>* p;
	for (p = header->succ; p != header;)
	{
		Node<T>* temp = p;
		p = p->succ;
		delete temp;
	}
	delete header;
}

template <typename T>
typename List_for_pool<T>::iterator List_for_pool<T>::insert(iterator p, Node<T>* pn)
{
	//将节点 n 插到 p 的前面,不释放节点
	Node<T>* temp = p.get_pnode();
	pn->pred = temp;
	pn->succ = temp->succ;
	temp->succ->pred = pn;		//因为是循环链表,不用检查是否为空
	temp->succ = pn;
	++sz;
	return iterator{ pn };
}

template <typename T>
typename List_for_pool<T>::iterator List_for_pool<T>::erase(iterator p)
{
	//将 p 位置节点删除,不释放节点
	if (begin() == end())
		return end();
	if (p == end())
		return end();
	Node<T>* np = p.get_pnode();
	Node<T>* q = np->succ;
	q->pred = np->pred;
	np->pred->succ = q;
	--sz;
	return iterator{ q };
}

template <typename T>
void List_for_pool<T>::push_back(const T& v)
{
	//在链表末尾插入元素,新建节点(需要动态内存分配)
	Node<T>* pnode = new Node<T>;
	pnode->val = v;
	header->pred->succ = pnode;
	pnode->succ = header;
	pnode->pred = header->pred;
	header->pred = pnode;
	++sz;
}



template<typename T, int N>
class Pool_v2
{
	size_t sz;			//存储池总数量
	T* space;			//内存空间,N个T对象
	List_for_pool<T*> lst_unalloc;	//链表元素指向空闲对象
	List_for_pool<T*> lst_alloc;	//链表元素指向已分配对象
							//设置已分配链表的目的是为了防止重复创建节点
							//创建节点会调用动态内存分配
public:
	Pool_v2();				//创建N个T的存储池
	T* get();				//从存储池获取一个T,若无空闲T则返回0
	void free(T*);			//将get()获得的一个T归还存储池
	int available() const	//空闲T的数目
	{
		return lst_unalloc.size();
	}
	~Pool_v2();
};

template<typename T, int N>
Pool_v2<T, N>::Pool_v2()
	:sz{ N }, space{ new T [N] },
	lst_unalloc{}, lst_alloc{}
{
	for (size_t i = 0; i < N; ++i)
		lst_unalloc.push_back(space + i);
}

template<typename T, int N>
T* Pool_v2<T, N>::get()
{
	//O(1)分配时间
	if (lst_unalloc.size() == 0)
		return 0;
	//将空闲链表的第一个元素分配出去
	auto np = lst_unalloc.begin();
	Node<T*>* pnode = np.get_pnode();
	lst_unalloc.erase(np);
	//将节点插入到已分配对象链表的头部
	lst_alloc.insert(lst_alloc.begin(), pnode);
	return pnode->val;
}

template<typename T, int N>
void Pool_v2<T, N>::free(T* obj)
{
	//释放慢,需要先从已分配链表中找到该节点并删除,之后插入到空闲链表的正确位置
	//遇到随机释放就特别慢
	//*obj = T{};		//将归还的对象设置为默认值
	for(auto pla = lst_alloc.begin(); pla != lst_alloc.end(); ++pla)
		if(*pla == obj)	//找到了
		{
			for (auto plua = lst_unalloc.begin(); plua != lst_unalloc.end(); ++plua)
				if (*plua > obj)	//空闲链表按内存位置从小到大排序
					lst_unalloc.insert(plua, pla.get_pnode());
		}
}

template <typename T, int N>
Pool_v2<T, N>::~Pool_v2()
{
	delete[] space;
}

Stack.h

用 bitset 跟踪和标记每个对象的首地址索引

#include <iostream>
#include <bitset>

using std::cerr;
using std::bitset;

template<int N>class Stack { // stack of N bytes
public:
    Stack();                 // make an N byte stack
    void* get(int n);        // allocate n bytes from the stack; 
                             // return 0 if no free space
    void free();             // return the last value returned by get() to the stack
    int available() const;   // number of available bytes
private:
    int sz;                 // total size of bytes
    int free_sz;            // size of available bytes
    int top;                // top of stack pointer which points to first byte of unallocated area
    bitset<N> flag;         // N位标记N字节,为1说明这个字节是已分配对象的第一个字节
	char* space;          // stack space

    // 为了跟踪分配的
};

template <int N>
Stack<N>::Stack()
    :sz{ N }, free_sz{ N }, top{0},
    flag{ 0 }, space{ new char[N] }
{
}

template <int N>
void* Stack<N>::get(int n)
{
    if(n < 0)
    {
        cerr << "non-positive size\n";
        return nullptr;
    }
    else if (n > free_sz)
    {
        cerr << "no enough space\n";
        return nullptr;
    }
    char* ret = &space[top];
    flag.set(top);
    top += n;
    free_sz -= n;

    return static_cast<void*>(ret);
}

template <int N>
void Stack<N>::free()
{
    if (top == 0)   //栈已经是空的
        return;
    
    //接下来遍历 flag,寻找栈顶对象的第一个字节位置
    size_t i;
	for(i = top-1; i >= 0; --i)
    {
        //space[i] = 0xCC;    //清除数据,可选的操作 
        if (flag.test(i))
            break;
    }
    size_t n{ top - i };     //栈顶对象的大小
    top = i;
    flag.set(top, false);   // == flag.reset(top);
    free_sz += n;
}

template <int N>
int Stack<N>::available() const
{
    return free_sz;
}

25.2

#include "../../std_lib_facilities.h"

int main()
try
{
	//初始化一个映射向量,将数字(索引)映射为英文字母串
	const vector<string> n2c{
		"o","l","to","three","for","five","six","seven",
		"eight", "nine", "a", "b", "c", "d", "e", "f" };
	const size_t base = n2c.size();

	//设置为读入十六进制数字,并能够正确解释前缀0x
	cin.unsetf(ios::dec | ios::oct);
	cin >> hex;
	int num{ -1 };
	cin >> num;
	while(num < 0)
	{
		cout << "number must be positive, try again\n";
		cin >> num;
	}

	//接下来对数字进行转换为英文字母串
	vector<string>temp;	//临时存放每一位十六进制数对应的英文字母串,从低位到高位
	if (num == 0)
		temp.push_back(n2c[num]);
	while(num > 0)
	{
		vector<string>::size_type i = num % base;
		temp.push_back(n2c[i]);
		num /= base;
	}

	//将逆序变成顺序
	reverse(temp.begin(), temp.end());

	//第一个字符串的第一个字母大写
	temp[0][0] = toupper(temp[0][0]);

	//输出
	for (const string& s : temp)
		cout << s;
	cout << '\n';

	return 0;
}
catch(runtime_error& e)
{
	cerr << "Runtime error: " << e.what() << endl;
	return 1;
}
catch(...)
{
	cerr << "Exception occurred!\n";
	return 2;
}

25.3

#include <bitset>
#include "../../std_lib_facilities.h"

int main()
try
{
    const size_t hex_bits{ 2 };  //一个字节对应两位十六进制数
    //32位有符号整数
    {
        int x;
        bitset<8 * sizeof(x)> b;
        //全0
        b = 0;
        x = 0;
        cout << dec << "decimal: " << setw(10) << x << hex << "\thex: 0x"
            << setw(sizeof(x) * hex_bits) << setfill('0') << x
            << "\tbin: " << b << '\n';
        //全1
        x = -1;
        b = x;
        cout << dec << "decimal: " << setw(10) << x << hex << "\thex: 0x"
            << setw(sizeof(x) * hex_bits) << setfill('0') << x
            << "\tbin: " << b << '\n';
        //1和0交替(最高有效位为1)
        x = 0xaaaaaaaa;
        b = x;
        cout << dec << "decimal: " << setw(10) << x << hex << "\thex: 0x"
            << setw(sizeof(short unsigned int) * 2) << setfill('0') << x
            << "\tbin: " << b << '\n';
        //0和1交替(最高有效位为0)
        x = 0x55555555;
        b = x;
        cout << dec << "decimal: " << setw(10) << x << hex << "\thex: 0x"
            << setw(sizeof(short unsigned int) * 2) << setfill('0') << x
            << "\tbin: " << b << '\n';
        //两个1和两个0交替
        x = 0xcccccccc;
        b = x;
        cout << dec << "decimal: " << setw(10) << x << hex << "\thex: 0x"
            << setw(sizeof(short unsigned int) * 2) << setfill('0') << x
            << "\tbin: " << b << '\n';
        //两个0和两个1交替
        x = 0x33333333;
        b = x;
        cout << dec << "decimal: " << setw(10) << x << hex << "\thex: 0x"
            << setw(sizeof(short unsigned int) * 2) << setfill('0') << x
            << "\tbin: " << b << '\n';
        //全1字节和全0字节交替
        x = 0xff00ff00;
        b = x;
        cout << dec << "decimal: " << setw(10) << x << hex << "\thex: 0x"
            << setw(sizeof(short unsigned int) * 2) << setfill('0') << x
            << "\tbin: " << b << '\n';
        //全0字节和全1字节交替
        x = 0x00ff00ff;
        b = x;
        cout << dec << "decimal: " << setw(10) << x << hex << "\thex: 0x"
            << setw(sizeof(short unsigned int) * 2) << setfill('0') << x
            << "\tbin: " << b << '\n';
    }

    cout << "\n\n";

    //无符号重做
    {
        unsigned int x{ 0 };
        bitset<8 * sizeof(x)> b;
        //全0
        b = 0;
        x = 0;
        cout << dec << "decimal: " << setw(10) << x << hex << "\thex: 0x"
            << setw(sizeof(x) * hex_bits) << setfill('0') << x
            << "\tbin: " << b << '\n';
        //全1
        x = -1;
        b = x;
        cout << dec << "decimal: " << setw(10) << x << hex << "\thex: 0x"
            << setw(sizeof(x) * hex_bits) << setfill('0') << x
            << "\tbin: " << b << '\n';
        //1和0交替(最高有效位为1)
        x = 0xaaaaaaaa;
        b = x;
        cout << dec << "decimal: " << setw(10) << x << hex << "\thex: 0x"
            << setw(sizeof(short unsigned int) * 2) << setfill('0') << x
            << "\tbin: " << b << '\n';
        //0和1交替(最高有效位为0)
        x = 0x55555555;
        b = x;
        cout << dec << "decimal: " << setw(10) << x << hex << "\thex: 0x"
            << setw(sizeof(short unsigned int) * 2) << setfill('0') << x
            << "\tbin: " << b << '\n';
        //两个1和两个0交替
        x = 0xcccccccc;
        b = x;
        cout << dec << "decimal: " << setw(10) << x << hex << "\thex: 0x"
            << setw(sizeof(short unsigned int) * 2) << setfill('0') << x
            << "\tbin: " << b << '\n';
        //两个0和两个1交替
        x = 0x33333333;
        b = x;
        cout << dec << "decimal: " << setw(10) << x << hex << "\thex: 0x"
            << setw(sizeof(short unsigned int) * 2) << setfill('0') << x
            << "\tbin: " << b << '\n';
        //全1字节和全0字节交替
        x = 0xff00ff00;
        b = x;
        cout << dec << "decimal: " << setw(10) << x << hex << "\thex: 0x"
            << setw(sizeof(short unsigned int) * 2) << setfill('0') << x
            << "\tbin: " << b << '\n';
        //全0字节和全1字节交替
        x = 0x00ff00ff;
        b = x;
        cout << dec << "decimal: " << setw(10) << x << hex << "\thex: 0x"
            << setw(sizeof(short unsigned int) * 2) << setfill('0') << x
            << "\tbin: " << b << '\n';
    }

    return 0;
}
catch (runtime_error& e)
{
    cerr << "Runtime error: " << e.what() << endl;
    return 1;
}
catch (...)
{
    cerr << "Exception occurred!\n";
    return 2;
}

25.4 Calculator

由于位运算只能用于整型,因此把计算器修改为整型运算计算器

/*
	25_4-Calculator.cpp

	本程序实现了一个简单的表达式计算器,支持变量操作,添加了帮助信息
	添加了位运算,根据优先级设置语法。
	~优先级最高,在Primary中,& ^ | 优先级以此降低,且他们三个都低于加法和减法符号
	位运算只能整型,所以我就把所有的double替换为int了
	从cin读入,输出到cout。

	输入文法如下:
		Calculation:
			Statement
			Print
			Quit
			Calculation Statement

		Print:
			';'

		Quit:
			'q'
			"quit"

		Statement:
			Declaration
			Expression_bit_or

		Declaration:
			"let" name '=' Expression
			"const" name '=' Expression

		//Expression_bit_or,意味着表达式中可能带有位运算符
			
		Expression_bit_or
			Expression_bit_xor
			Expression_bit_or '|' Expression_bit_xor

		Expression_bit_xor
			Expression_bit_and
			Expression_bit_xor '^' Expression_bit_and

		Expression_bit_and
			Expression
			Expression_bit_and '&' Expression
		
		Expression:
			Term
			Expression '+' Term
			Expression '-' Term

		Term:
			Primary
			Term * Primary
			Term / Primary
			Term % Primary

		Primary:
			Number
			'(' Expression_bit_or ')'
			-Primary	//处理负数
			~Primary	//按位取反
			Assignment

		Number:
			floating-point-literal

		Assignment:
			name '=' Expression

*/

#include "../../std_lib_facilities.h"

struct Token {
	char kind;
	int value;
	string name;
	Token(char ch) :kind(ch), value(0) { }
	Token(char ch, int val) :kind(ch), value(val) { }
	Token(char ch, string n) :kind(ch), name(n) { }
};

class Token_stream {
private:
	bool full;
	Token buffer;
public:
	Token_stream() :full(false), buffer(0) { }	// The constructor just sets full to indicate that the buffer is empty:

	Token get();
	void putback(Token t);
	void ignore(char);
};

const string declkey = "let";
const char let = 'L';
const string quitkey = "quit";
const char quit = 'q';
const string helpkey = "help";
const char help = 'h';
const char print = ';';
const char number = '8';
const char name = 'a';
const char assign = '=';
const char con = 'C';
const string constkey = "const";

Token Token_stream::get()
{
	if (full)
	{
		full = false;
		return buffer;
	}
	char ch;
	//cin >> ch;	// note that >> skips whitespace (space, newline, tab, etc.)
	while (isspace((ch = cin.get())) && ch != '\n')
		continue;

	switch (ch) {
	case '(': case ')':
	case '+': case '-':
	case '*': case '/': case '%':
	case '~': case '&': case '^': case '|':
	case '=':
	case quit:
	case print:
		return Token{ ch };	// let each character represent itself
	case '\n':
		return Token{ print };
	case '.':
	case '0': case '1': case '2': case '3':	case '4':
	case '5': case '6': case '7': case '8': case '9':
	{
		cin.putback(ch);	// put digit back into the input stream
		//cin.unget();	// same as putback(char), except no parameter
		int val;
		cin >> val;		// read a floating-point number
		return Token{ number, val };
	}
	default:
		if (isalpha(ch)) {
			string s;
			s += ch;
			//名字为字母开头的,带字母数字和下划线的字符串
			while (cin.get(ch) && (isalpha(ch) || isdigit(ch) || ch == '_'))
				s += ch;
			cin.putback(ch);
			if (s == declkey) return Token{ let };	// 声明变量关键字
			if (s == constkey) return Token{ con };	// 声明常量关键字
			if (s == helpkey || (s.size() == 1 && s[0] == help)) return Token{ help };
			if (s == quitkey) return Token{ quit };
			return Token{ name, s };
		}
		error("Bad token");
	}
}

// The putback() member function puts its argument back into the Token_stream's buffer:
void Token_stream::putback(Token t)
{
	if (full)
		error("putback() into a full buffer.");
	buffer = t;
	full = true;
}

void Token_stream::ignore(char c)
{
	if (full && c == buffer.kind) {
		full = false;
		return;
	}
	full = false;

	char ch;
	while (cin >> ch)
		if (ch == c) return;
}


//---------------------------------------------------------
// set Variable
class Variable {
public:
	string name;
	int value;
	bool is_const;
	Variable(string n, int v, bool b) :name(n), value(v), is_const(b) { }
};
class Symbol_table {
public:
	Symbol_table() {}
	int get(string var);
	void set(string var, int d);
	bool is_declared(string var);
	int define(string var, int val, bool is_const);
private:
	vector<Variable> var_table;
};

int Symbol_table::get(string s)
{
	for (const Variable& v : var_table)
		if (v.name == s)
			return v.value;
	error("get: undefined name ", s);
}

void Symbol_table::set(string s, int d)
{
	for (Variable& v : var_table)
		if (v.name == s)
		{
			if (v.is_const)
				error("set: can not assign to a const ", s);
			v.value = d;
			return;
		}
	error("set: undefined name ", s);
}

bool Symbol_table::is_declared(string var)
{
	//判断var是否已经在var_table中了
	for (const Variable& v : var_table)
		if (v.name == var)
			return true;
	return false;
}

int Symbol_table::define(string var, int val, bool is_const)
{
	//将(var, val)加入var_table中
	if (is_declared(var))
		error(var, " declared twice");
	var_table.push_back(Variable{ var, val, is_const });
	return val;
}

Token_stream ts;
Symbol_table st;

//--------Expression---------------
int expression_bit_or();
int expression_bit_xor();
int expression_bit_and();
int expression();

int assignment(string var)
{
	// 函数假设已经读入了赋值语句的左值和赋值符号

	int right = expression();
	st.set(var, right);
	return right;
}

int primary()
{
	Token t = ts.get();
	switch (t.kind) {
	case '(':
	{
		int d = expression_bit_or();
		t = ts.get();
		if (t.kind != ')')
			error("'(' expected");
		return d;
	}
	case '-':
		return -primary();
	case '~':	//按位取反
		return ~primary();
	case number:
		return t.value;
	case name:
	{
		Token t2 = ts.get();
		if (t2.kind != assign)
		{
			ts.putback(t2);
			return st.get(t.name);	// if next char is not a assignment operator, then return variable value
		}
		else
			return assignment(t.name);
	}
	default:
		error("primary expected");
	}
}

int term()
{
	int left = primary();
	while (true) {
		Token t = ts.get();
		switch (t.kind) {
		case '*':
			left *= primary();
			break;
		case '/':
		{
			int d = primary();
			if (d == 0) error("divide by zero");
			left /= d;
			break;
		}
		case '%':
		{
			int d = primary();
			if (d == 0) error("divide by zero");
			left = fmod(left, d);
			break;
		}
		default:
			ts.putback(t);
			return left;
		}
	}
}

int expression()
{
	int left = term();
	while (true) {
		Token t = ts.get();
		switch (t.kind) {
		case '+':
			left += term();
			break;
		case '-':
			left -= term();
			break;
		default:
			ts.putback(t);
			return left;
		}
	}
}

int expression_bit_and()
{
	int left = expression();
	while (true) {
		Token t = ts.get();
		if (t.kind == '&')
			left &= expression();
		else
		{
			ts.putback(t);
			return left;
		}
	}
}

int expression_bit_xor()
{
	int left = expression_bit_and();
	while (true) {
		Token t = ts.get();
		if (t.kind == '^')
			left ^= expression_bit_and();
		else
		{
			ts.putback(t);
			return left;
		}
	}
}

int expression_bit_or()
{
	int left = expression_bit_xor();
	while(true) {
		Token t = ts.get();
		if (t.kind == '|')
			left |= expression_bit_xor();
		else
		{
			ts.putback(t);
			return left;
		}
	}
}

int declaration(char kind)
{
	Token t = ts.get();
	if (t.kind != name)
		error("name expected in declaration");
	string var_name = t.name;

	Token t2 = ts.get();
	if (t2.kind != '=')
		error("= missing in declaration of ", var_name);

	int d = expression_bit_or();
	bool is_const = kind == con;
	st.define(var_name, d, is_const);

	return d;
}


int statement()
{
	Token t = ts.get();
	switch (t.kind) {
	case let:
	case con:
		return declaration(t.kind);
	default:
		ts.putback(t);
		return expression_bit_or();
	}
}

void clean_up_mess()
{
	ts.ignore(print);
}

const string prompt = "> ";
const string result = "= ";

void help_message()
{
	cout << "Please enter expressions using floating-point numbers.\n";
	cout << "You can use \"+ - * / %\" operators, ";
	cout << "';' or type in Enter to output result, 'h' to help, and 'q' to quit.\n";
	cout << "You can also define variables and constant by using let and const" << endl;
	cout << "For example: let a = 1 define a variable a, const b = a * 3 define a constant b" << endl;
}

void calculate()
{
	while (true)
		try {
		cout << prompt;
		Token t = ts.get();
		while (t.kind == print) t = ts.get();	// 丢弃之前的所有打印字符
		if (t.kind == quit) return;
		if (t.kind == help)
		{
			help_message();
			continue;
		}
		ts.putback(t);
		cout << result << statement() << endl;
	}
	catch (runtime_error& e) {
		cerr << e.what() << endl;
		clean_up_mess();
	}
}

int main()
try {
	cout << "Welcome to our simple calculator.\n";
	cout << "Please enter expressions using floating-point numbers.\n";
	cout << "You can use \"+ - * / %\" operators, ';' to output result, 'h' to help, and 'q' to quit.\n";
	cout << "You can also define variables and constant by using let and const" << endl;
	cout << "For example: let a = 1 define a variable a, const b = a * 3 define a constant b" << endl;

	calculate();
	return 0;
}
catch (exception& e) {
	cerr << "exception: " << e.what() << endl;
	char c;
	while (cin >> c && c != ';');
	return 1;
}
catch (...) {
	cerr << "exception\n";
	char c;
	while (cin >> c && c != ';');
	return 2;
}

25.5 and 25.6 较难发现的无限循环

#include "../../std_lib_facilities.h"

int main()
try
{

    //这是一个无限循环,为什么呢?
	//需要反汇编解释,变量 i 的值mov到寄存器是 movsx
	//而变量 max 的值mov到寄存器是 movzx
	//由于 i 是有符号数,因此当超过127后,movsx 的效果是把 i 的值进行符号拓展后放到寄存器
	//所以存放 i 的寄存器的高位是 1,而此时存放 max 的寄存器的高位是 0
	//但是 i < max 这个判断是否跳出循环的比较,VS2019编译器用的指令是 jge
	//那么只要 max 超过128,i jge 的结果必然表明 i < max,所以无限循环
    unsigned char max = 128;
    for (signed char i = 0; i < max; ++i)
        cout << int(i) << '\n';

    //下面的不会无限循环,因为 能满足 jge,所以循环会结束
    unsigned int max2 = 1 << 31;;
    for (signed int i = 0; i < max2; ++i)
        cout << int(i) << '\n';

    //我认为这个无限循环特性与编译器有关,可能换一种编译器就不会无限循环了
    return 0;
}
catch (runtime_error& e)
{
    cerr << "Runtime error: " << e.what() << endl;
    return 1;
}
catch (...)
{
    cerr << "Exception occurred!\n";
    return 2;
}

25.7

#include "../../std_lib_facilities.h"

int main()
try
{
	for (int i = 0; i <= 400; ++i)
		cout << dec << setw(5) << i << hex << setw(10) << i << '\n';

	cout << '\n';

	for(int i = -200; i <= 200; ++i)
		cout << dec << setw(5) << i << hex << setw(10) << i << '\n';

	return 0;
}
catch (runtime_error& e)
{
	cerr << "Runtime error: " << e.what() << endl;
	return 1;
}
catch (...)
{
	cerr << "Exception occurred!\n";
	return 2;
}

25.8

#include "../../std_lib_facilities.h"

int main()
try
{
	cout << "Enter character on your keyboard\n";
	char ch;
	while (cin.get(ch))
		cout << ch << ": " << int(ch) << '\n';

	return 0;
}
catch (runtime_error& e)
{
	cerr << "Runtime error: " << e.what() << endl;
	return 1;
}
catch (...)
{
	cerr << "Exception occurred!\n";
	return 2;
}

25.9

#include "../../std_lib_facilities.h"

int main()
try
{
	//确定 int 包含多少位
	int cnt{ 0 };
	int i = 0;
	for (i = ~i; i != 0; i <<= 1)
		++cnt;
	cout << "int is " << cnt << " bits\n";

	//确定 char 是有符号的还是无符号的
	cnt = 0;
	char j = 0;
	for (j = ~j; j != 0; j <<= 1)
		++cnt;
	cout << "char is " << cnt << " bits\n";
	char j1 = 1 << (cnt - 1);
	char j2 = ~j1;
	if (j1 > j2)
		cout << "char is unsigned\n";
	else
		cout << "char is signed\n";

	return 0;
}
catch (runtime_error& e)
{
	cerr << "Runtime error: " << e.what() << endl;
	return 1;
}
catch (...)
{
	cerr << "Exception occurred!\n";
	return 2;
}

25.10 and 25.11 位域,无符号数位运算,bitset<>

#include "../../std_lib_facilities.h"
#include <bitset>

struct PPN
{
	unsigned int PFN : 22;	//页帧号
	int : 3;				//未用,因此未命名
	unsigned int CCA : 3;	//协同缓存算法
	bool nonreachable : 1;
	bool dirty : 1;
	bool valid : 1;
	bool global : 1;
};

void print_ppn(struct PPN& ppn)
{
	cout << "PFN: " << ppn.PFN << '\n';
	cout << "CCA: " << ppn.CCA << '\n';
	cout << "nonreachable: " << boolalpha << ppn.nonreachable << '\n';
	cout << "dirty: " << ppn.dirty << '\n';
	cout << "valid: " << ppn.dirty << '\n';
	cout << "global: " << ppn.global << '\n';
	cout << noboolalpha;
}

void print_ppn(const unsigned int ppn)
{
	cout << "PFN: " << ((ppn>>10) & 0x3FFF) << '\n';
	cout << "CCA: " << ((ppn >> 4) & 0x7) << '\n';
	cout << "nonreachable: " << boolalpha << ((ppn >> 3) & 0x1) << '\n';
	cout << "dirty: " << ((ppn >> 2) & 0x1) << '\n';
	cout << "valid: " << ((ppn >> 1) & 0x1) << '\n';
	cout << "global: " << (ppn & 0x1) << '\n';
	cout << noboolalpha;
}

void print_ppn(const bitset<32> ppn)
{
	bitset<32> pfn_mask{ 0xfffffc00 };
	cout << "PFN: " << ((ppn & pfn_mask) >> 10).to_ulong() << '\n';
	bitset<32> cca_mask{ 0x70 };
	cout << "CCA: " << ((ppn & cca_mask) >> 4).to_ulong() << '\n';
	cout << "nonreachable: " << boolalpha << ppn[3] << '\n';
	cout << "dirty: " << ppn[2] << '\n';
	cout << "valid: " << ppn[1] << '\n';
	cout << "global: " << ppn[0] << '\n';
	cout << noboolalpha;
}

int main()
try
{
	//用位域 bitfield 表示 PPN
	PPN ppn1{ 256, 7,false,true,true,false };
	print_ppn(ppn1);
	cout << '\n';

	ppn1.PFN = 0xff;
	ppn1.CCA = 5;
	ppn1.nonreachable = true;
	ppn1.dirty = !ppn1.dirty;
	ppn1.valid = !ppn1.valid;
	ppn1.global = !ppn1.global;
	print_ppn(ppn1);
	cout << '\n';

	
	//用32位无符号数表示 PPN
	cout << "32 bits unsigned\n";
	unsigned int ppn2{ 0x00040076 };
	print_ppn(ppn2);
	cout << '\n';

	ppn2 = (0xff << 10) | (0x5 << 4) | (0x1 << 3) | (0x0 << 2) | (0x0 << 1) | 0x1;
	print_ppn(ppn2);
	cout << '\n';


	//用 bitset<32>
	cout << "bitset<32>\n";
	bitset<32> ppn3 { string{"00000000000001000000000001110110"} };
	print_ppn(ppn3);
	cout << '\n';

	//设置新的pfn
	bitset<32> pfn_mask{ 0xfffffc00 };
	ppn3 &= ~pfn_mask;
	ppn3 |= 0xff << 10;
	//设置新的cca
	bitset<32> cca_mask{ 0x70 };
	ppn3 &= ~cca_mask;
	ppn3 |= 5 << 4;
	//设置其余标识位
	ppn3.set(3);
	ppn3.reset(2);
	ppn3.flip(1);
	ppn3[0] = true;
	print_ppn(ppn3);
	cout << '\n';
	
	return 0;
}
catch (runtime_error& e)
{
	cerr << "Runtime error: " << e.what() << endl;
	return 1;
}
catch (...)
{
	cerr << "Exception occurred!\n";
	return 2;
}

25.12

这个我就直接用了随书的源代码了


//
// This is example code from Chapter 25.5.6 "An Example: Simple encryption" of
// "Programming -- Principles and Practice Using C++" by Bjarne Stroustrup
//

#include "../../std_lib_facilities.h"

//------------------------------------------------------------------------------

void encipher(
    const unsigned long *const v,
    unsigned long *const w,
    const unsigned long * const k)
{
    unsigned long y = v[0];
    unsigned long z = v[1];
    unsigned long sum = 0;
    unsigned long delta = 0x9E3779B9;
    unsigned long n = 32;
    while(n-->0) {
        y += (z << 4 ^ z >> 5) + z ^ sum + k[sum&3];
        sum += delta;
        z += (y << 4 ^ y >> 5) + y ^ sum + k[sum>>11 & 3];
    }
    w[0]=y; w[1]=z;
}

//------------------------------------------------------------------------------

// Here is the corresponding deciphering function:
void decipher(
    const unsigned long *const v,
    unsigned long *const w,
    const unsigned long * const k)
{ 
    unsigned long y = v[0];
    unsigned long z = v[1];
    unsigned long sum = 0xC6EF3720;
    unsigned long delta = 0x9E3779B9;
    unsigned long n = 32;
    // sum = delta<<5, in general sum = delta * n
    while(n-->0) {
        z -= (y << 4 ^ y >> 5) + y ^ sum + k[sum>>11 & 3];
        sum -= delta;
        y -= (z << 4 ^ z >> 5) + z ^ sum + k[sum&3];
    }
    w[0]=y; w[1]=z;
}

//------------------------------------------------------------------------------

int main()    // reciever
try
{
    const int nchar = 2*sizeof(long);    // 64 bits
    const int kchar = 2*nchar;           // 128 bits

    string op;
    string key;
    string infile;
    string outfile;
    cout << "please enter inputfile name, output file name, and key:\n";
    cin >> infile >> outfile >> key;
    while (key.size()<kchar) key += '0'; // pad key
    ifstream inf(infile.c_str());
    ofstream outf(outfile.c_str());
    if (!inf || !outf) error("bad file name");

    const unsigned long* k =
        reinterpret_cast<const unsigned long*>(key.data());

    unsigned long inptr[2];    
    char outbuf[nchar+1];
    outbuf[nchar]=0; // terminator
    unsigned long* outptr = reinterpret_cast<unsigned long*>(outbuf);
    inf.setf(ios_base::hex ,ios_base::basefield); // use hexadecimal input

    while (inf>>inptr[0]>>inptr[1]) {
        decipher(inptr,outptr,k);
        outf<<outbuf;
    }
}
catch (exception& e) {
    cerr << "error: " << e.what() << '\n'; 
    return 1;
}
catch (...) {
    cerr << "Oops: unknown exception!\n"; 
    return 2;
}

25.14 Vector, Pool 作为分配器

感觉题意有些不清晰

#include <iostream>
#include "Pool.h"

using namespace std;

template<typename T, int N, typename Alloc = Pool_v1<T, N>> 	//Pool_v2也可以
class vector
{
	Alloc alloc;
	size_t sz;
	T* elem[N];		//跟踪对象的指针数组

public:
	vector();

	T& operator[](int n);
	void push_back(const T& elem);
	int size() const { return sz; }
};

template <typename T, int N, typename Alloc>
vector<T, N, Alloc>::vector()
	:alloc{}, sz{ 0 }
{}

template <typename T, int N, typename Alloc>
T& vector<T, N, Alloc>::operator[](int n)
{
	//不提供范围检查
	return *elem[n];
}

template <typename T, int N, typename Alloc>
void vector<T, N, Alloc>::push_back(const T& v)
{
	if(sz == N)
	{
		cerr << "no enough space\n";
		return;
	}
	elem[sz] = alloc.get();
	*elem[sz] = v;
	++sz;
}



int main()
{
	vector<int, 10> pv1;
	pv1.push_back(5);
	cout << "pv1.size(): " << pv1.size() << '\n';
	cout << "pv1[0]: " << pv1[0] << '\n';

	vector<int, 1000> pv2;
	for (int i = 0; i < 1000; ++i)
		pv2.push_back(i);
	for (size_t i = 0; i < pv2.size(); ++i)
		cout << pv2[i] << '\n';
	cout << "pv2.size(): " << pv2.size() << '\n';

	return 0;
}

25.15 测试 new / delete, Pool, Stack 的分配与释放速度

产生随机序列的算法很有意思

#include <chrono>
#include<iostream>
#include<ctime>
#include<cstdlib>
#include<string>
#include<vector>
#include<algorithm>
#include<random>
#include<stdexcept>
#include "Pool.h"
#include "Stack.h"

using namespace std;
using namespace chrono;

inline int randint(int min, int max)
{
	static default_random_engine ran(time(0));
	return uniform_int_distribution<>{min, max}(ran);
}

inline int randint(int max) { return randint(0, max); }

inline void test_new_v1(int repn);
inline void test_new_v2(int repn);
inline void test_Pool_v1(int repn);
inline void test_Pool_v2(int repn);
inline void test_Stack(int repn);

int main()
{
    const int repn{ 1000 };     //重复次数
    //test_new_v1(repn);
    //test_new_v2(repn);
    //test_Pool_v1(repn);
    //test_Pool_v2(repn);
    test_Stack(repn);

	return 0;
}

inline void test_new_v1(int repn)
{
    //用 new 分配10000个对象所花费时间,对象大小为1字节到1000字节之间的随机值,
    //然后用 delete 按分配的逆序进行释放,测试时间。
    //参数 repn为重复次数

    const int n_objs{ 10000 };
    const int min_obj_sz{ 1 };
    const int max_obj_sz{ 1000 };

    vector<char*> v1(n_objs); //存储 n_objs 个对象指针

    //开始计时
    auto t1 = system_clock::now();
    for (int i = 0; i < repn; ++i)
    {
        for (vector<char*>::size_type i = 0; i < v1.size(); ++i)
        {
            size_t alloc_sz = randint(min_obj_sz, max_obj_sz);
            v1[i] = new char[alloc_sz];
        }
        //按分配的逆序进行释放   
        for (vector<char*>::size_type i = v1.size() - 1; i < v1.size(); --i)
            delete[] v1[i];
    }
	auto t2 = system_clock::now();
    //计时结束

    cout << "Allocating " << n_objs << " objects by new "
		<< "and delete by reverse order " << repn <<" times took "
        << duration_cast<milliseconds>(t2 - t1).count() << " milliseconds\n";
}

inline void test_new_v2(int repn)
{
    //用 new 分配10000个对象所花费时间,对象大小为1字节到1000字节之间的随机值,
    //然后用 delete 按随机顺序进行释放,测试时间
    //参数 repn为重复次数

    const int n_objs{ 10000 };
    const int min_obj_sz{ 1 };
    const int max_obj_sz{ 1000 };

    vector<char*> v1(n_objs); //存储 n_objs 个对象指针

    //获得随机释放的序列顺序
    vector<vector<char*>::size_type> v_rand_i(v1.size());
    for (vector<char*>::size_type i = 0; i < v_rand_i.size(); ++i)
        v_rand_i[i] = i;
    for (vector<char*>::size_type i = 1; i < v_rand_i.size(); ++i)
        swap(v_rand_i[i], v_rand_i[randint(i)]);

    //开始计时
    auto t1 = system_clock::now();
    for (int i = 0; i < repn; ++i)
    {
        for (vector<char*>::size_type i = 0; i < v1.size(); ++i)
        {
            size_t alloc_sz = randint(min_obj_sz, max_obj_sz);
            v1[i] = new char[alloc_sz];
        }
        //按随机顺序进行释放
        for (const int i : v_rand_i)
            delete[] v1[i];
    }
    auto t2 = system_clock::now();
    //计时结束

    cout << "Allocating " << n_objs << " objects by new "
        << "and delete by random order " << repn << " times took "
        << duration_cast<milliseconds>(t2 - t1).count() << " milliseconds\n";
}

//500字节的对象
struct Obj500
{
    char c[500];
};

void test_Pool_v1(int repn)
{
    //从存储池 Pool_v1 中分配 10,000 个大小固定为 500 字节的对象
    //然后 按随机顺序进行释放,测试时间
    //参数 repn为重复次数
    const int n_objs{ 10000 };

    Pool_v1<Obj500, n_objs> pool_v1;//存储池
    vector<Obj500*> v1(n_objs);     //存储 n_objs 个对象指针

    //获得随机释放的序列顺序
    vector<vector<char*>::size_type> v_rand_i(v1.size());
    for (vector<char*>::size_type i = 0; i < v_rand_i.size(); ++i)
        v_rand_i[i] = i;
    for (vector<char*>::size_type i = 1; i < v_rand_i.size(); ++i)
        swap(v_rand_i[i], v_rand_i[randint(i)]);

    //开始计时
    auto t1 = system_clock::now();
    for (int i = 0; i < repn; ++i)
    {
        for (vector<char*>::size_type i = 0; i < v1.size(); ++i)
            v1[i] = pool_v1.get();
        //按随机顺序进行释放
        for (const int i : v_rand_i)
            pool_v1.free(v1[i]);
    }
    auto t2 = system_clock::now();
    //计时结束

    cout << "Allocating " << n_objs << " objects by Pool_v1 "
        << "and delete by random order " << repn << " times took "
        << duration_cast<milliseconds>(t2 - t1).count() << " milliseconds\n";
}

void test_Pool_v2(int repn)
{
    //从存储池 Pool_v2 中分配 10,000 个大小固定为 500 字节的对象
	//然后 按随机顺序进行释放,测试时间
	//参数 repn为重复次数
    const int n_objs{ 10000 };

    Pool_v2<Obj500, n_objs> pool_v2;//存储池
    vector<Obj500*> v1(n_objs);     //存储 n_objs 个对象指针

    //获得随机释放的序列顺序
    vector<vector<char*>::size_type> v_rand_i(v1.size());
    for (vector<char*>::size_type i = 0; i < v_rand_i.size(); ++i)
        v_rand_i[i] = i;
    for (vector<char*>::size_type i = 1; i < v_rand_i.size(); ++i)
        swap(v_rand_i[i], v_rand_i[randint(i)]);

    //开始计时
    auto t1 = system_clock::now();
    for (int i = 0; i < repn; ++i)
    {
        for (vector<char*>::size_type i = 0; i < v1.size(); ++i)
            v1[i] = pool_v2.get();
        //按随机顺序进行释放,释放速度极慢
        for (const int i : v_rand_i)
            pool_v2.free(v1[i]);
    }
    auto t2 = system_clock::now();
    //计时结束

    cout << "Allocating " << n_objs << " objects by Pool_v2 "
        << "and delete by random order " << repn << " times took "
        << duration_cast<milliseconds>(t2 - t1).count() << " milliseconds\n";
}

void test_Stack(int repn)
{
    //从 Stack 中分配 10000 个大小为 1 字节 到 1000 字节之间随机数的对象
    //然后按逆序进行释放,测试时间
    //参数 repn为重复次数
    constexpr int n_objs{ 1000 };
    constexpr int min_obj_sz{ 1 };
    constexpr int max_obj_sz{ 1000 };

    Stack<n_objs* max_obj_sz> st;
    vector<char*> v1(n_objs);     //存储 n_objs 个对象指针

    
    //开始计时
    auto t1 = system_clock::now();
    for (int i = 0; i < repn; ++i)
    {
        for (vector<char*>::size_type i = 0; i < v1.size(); ++i)
        {
            size_t alloc_sz = randint(min_obj_sz, max_obj_sz);
            v1[i] = static_cast<char*>(st.get(alloc_sz));
        }
        //按分配的逆序进行释放,这里利用了栈的特性,无需指定专门的逆序索引
        for (vector<char*>::size_type i = 0; i < v1.size(); ++i)
            st.free();
    }
    auto t2 = system_clock::now();
    //计时结束

    cout << "Allocating " << n_objs << " objects by Pool_v2 "
        << "and delete by random order " << repn << " times took "
        << duration_cast<milliseconds>(t2 - t1).count() << " milliseconds\n";
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值