《C++ Primer》5th 课后练习 第六章 函数 11~20

练习 6.11 编写并验证你自己的reset函数,使其作用于引用类型的参数。

#include<iostream>
using namespace std;
void reset(int &a) {
	a = 0;
}
int main()
{
	int x = 10;
	cout << "x: " << x << endl;
	reset(x);
	cout << "x: " << x << endl;
	return 0;
}

练习 6.12 改写6.2.1节练习中的程序,使其引用而非指针交换两个整数的值。你觉得哪种方法更易于使用呢?为什么?

#include<iostream>
using namespace std;
void swap(int &a, int &b) {
	int tmp = a;
	a = b;
	b = tmp;
	return;
}
int main()
{
	int a = 1, b = 2;
	cout << "a: " << a << "\nb: " << b << endl;
	swap(a, b);
	cout << "a: " << a << "\nb: " << b << endl;
	return 0;
}

显然引用更好。

练习 6.13 假设 T 是某种类型的名字,说明以下两个函数声明的区别:一个是void f(T), 另一个是 void f(&T)

前者是传值,不能通过形参改变实参。

后者是传引用,可以通过形参改变实参。

ps:我觉得后面的那种写法应该是 void f(T &),直接用树上的写法会编译出错。

练习 6.14 举一个形参应该是引用类型的例子,再举一个形参不能是引用类型的例子。

交换两个变量的数值,形参需要用引用类型。

当不希望函数改变实参的值而函数中又会更改形参的值时,则形参不能用引用类型。

练习 6.15 说明find_char 函数中的三个形参为什么是现在的类型,特别说明为什么s是常量引用而occurs是普通引用?为什么soccurs是引用类型而c不是?如果令s是普通引用会发生什么情况?如果令occurs是常量引用会发生什么情况?

  • 使用传值方式的话,字符串复制的开销很大,所以传入引用;因为函数保证不会修改s的值,所以用const引用来加以限制。
  • 因为调用者是通过occurs来隐式地获得c的出现次数的,所以需要函数在其操作中修改occurs来进行计数并返回给调用者。
  • 因为c通常情况下会传入一个字面值,并且由于c仅仅是一个char类型,所以通过传值方式调用更方便快捷。
  • 在这个函数中不会发生特殊情况,但是如果不加const限制,则有可能会在函数中修改s变量。
  • 会导致函数不能正常修改occurs,导致错误。

练习 6.16 下面的这个函数虽然合法,但是不算特别有用。指出它的局限性并设法改善。

bool is_empty(string& s) { return s.empty(); }

局限性在于常量字符串字符串字面值无法作为它的实参

可以改为:

bool is_empty(const tring &s){return s.empty();}

练习 6.17 编写一个函数,判断string对象中是否含有大写字母。编写另一个函数,把string对象全部改写成小写形式。在这两个函数中你使用的形参类型相同吗?为什么?

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

bool haveupper(const string &s) {
	bool flag = false;
	for (auto c : s) {
		if (isupper(c)) {
			flag = true;
			break;
		}
	}
	return flag;
}

void beclower(string &s) {
	bool flag = false;
	for (auto &c : s) {
		c = tolower(c);
	}
}
int main()
{
	string a = "ABCDaaaa";
	cout << a << endl;
	cout << haveupper(a) << endl;
	beclower(a);
	cout << a << endl;
	cout << haveupper(a) << endl;

	return 0;
}

不同,因为函数的需求不同,第一个函数只需要访问字符串s即可,所以用const引用类型,而第二个函数需要访问并修改字符串s,所以用普通引用类型。

练习 6.18 为下面的函数编写函数声明,从给定的名字中推测函数具备的功能。

  • (a) 名为 compare 的函数,返回布尔值,两个参数都是 matrix 类的引用。
  • (b) 名为 change_val 的函数,返回vector的迭代器,有两个参数:一个是int,另一个是vector的迭代器。
bool compare(matrix &a, matrix &b);
vector<int>::iterator change_val(int x, vector<int>::iterator iter)

练习 6.19 假定有如下声明,判断哪个调用合法、哪个调用不合法。对于不合法的函数调用,说明原因。

double calc(double);
int count(const string &, char);
int sum(vector<int>::iterator, vector<int>::iterator, int);
vector<int> vec(10);
(a) calc(23.4, 55.1);
(b) count("abcda",'a');
(c) calc(66);
(d) sum(vec.begin(), vec.end(), 3.8);

(a)不合法,calc只有一个参数,调用时却传入了两个值。

(b)合法

©合法

(d)合法

练习 6.20 引用形参什么时候应该是常量引用?如果形参应该是常量引用,而我们将其设为了普通引用,会发生什么情况?

当只需要访问实参的值,而不需要更改实参时,一个用常量引用。

可能会导致本应该合法的调用不合法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章