C++ Primer 5th 随堂练习
【C++ Primer】第三章 字符串、向量和数组 (练习)
第六章 函数
练习 6.1
实参和形参的区别的什么?
解答
形参出现在函数定义的地方,形参列表可以包含 0 个或任意个形参,多个形参之间以逗号分隔,各形参均需明确类型。形参规定了一个函数所接受数据的类型和数量。
实参出现在函数调用的地方,实参的数量通常与形参一样多。实参的主要作用是初始化形参,并且这种初始化过程是一一对应的,即第一个实参初始化第一个形参、第二个实参初始化第二个形参,依此类推。实参的类型必须与对应的形参类型匹配。
练习 6.2
请指出下列函数哪个有错误,为什么?应该如何修改这些错误呢?
(a) int f() { string s; // ... return s; } (b) f2(int i) { /* ... */ } (c) int calc(int v1, int v1) { /* ... */ } (d) double square (double x) return x * x;
解答
// 函数类型与返回类型不匹配, 按原意应修改函数类型为 string:
(a) string f() {
string s;
// ...
return s;
}
// 未定义函数类型, 按原意应增加函数类型为 void:
(b) void f2(int i) { /* ... */ }
// 函数形参名不可以重复, 按原意修改其中一个形参名为 v2:
(c) int calc(int v1, int v2) { /* ... */ }
// 函数体没有包含在花括号内, 按原意应增加花括号:
(d) double square (double x) {return x * x;}
练习 6.3
编写你自己的 fact 函数,上机检查是否正确。注:阶乘。
解答
源程序 - 迭代实现:
#include <iostream>
#include <stdexcept>
using namespace std;
int fact (int val)
{
if (val < 0)
throw runtime_error ("Input cannot be a negative number"); // 输入负数抛出异常
int ret = 1;
while (val > 1)
ret *= val--;
return ret;
}
int main()
{
int num;
cin >> num;
int result = fact(num);
cout << result << endl;
system("pause");
return 0;
}
练习 6.4
编写一个与用户交互的函数,要求用户输入一个数字,计算生成该数字的阶乘。在 main 函数中调用该函数。
解答
源程序 - 递归实现:
#include <iostream>
#include <stdexcept>
using namespace std;
int fact (int val)
{ // return val > 1 ? (val * fact(val-1)) : 1;
if (val == 0)
return 1;
else
return val * fact(val-1);
}
int main()
{
int num;
cout << "input a integer to compute factorial: ";
cin >> num;
if (num < 0)
throw runtime_error ("input cannot be a negative number");
cout << "the factorial of " << num << " is " << fact(num) << endl;
system("pause");
return 0;
}
练习 6.5
编写一个函数输出其实参的绝对值。
解答
#include <iostream>
using namespace std;
int abs(int val)
{
return val < 0 ? -val : val;
}
int main()
{
int num;
cout << "input a integer to compute absolute value: ";
cin >> num;
cout << "the absolute value of " << num << " is " << abs(num) << endl;
system("pause");
return 0;
}
练习 6.6
说明形参、局部变量以及局部静态变量的区别。编写一个函数,同时达到这三种形式。
解答
// 举例
#include <iostream>
using namespace std;
int count_add(int n) // n 是形参
{
static int ctr = 0; // ctr 是局部静态变量
ctr += n;
return ctr;
}
int main()
{
for (int i = 0; i != 10; ++i) // i 是局部变量
cout << count_add(i) << endl;
system("pause");
return 0;
}
练习 6.7
编写一个函数,当它第一次被调用时返回 0,以后每次被调用返回值加1。
解答
#include <iostream>
using namespace std;
int func()
{
static int cnt = 0; // 局部静态变量
return (cnt++);
}
int main()
{
for (int i = 0; i < 3; ++i)
cout << func() << endl;
system("pause");
return 0;
}
输出:
0
1
2
练习 6.8 - Chapter6.h
编写一个名为 Chapter6.h 的 头文件,令其包含 6.1 节练习中的 函数声明。
解答
// Chapter6.h
#ifndef CHAPTER6_H_INCLUDE
#define CHAPTER6_H_INCLUDE
// function prototype
int fact(int );
int abs(int );
double myABS(double );
double myABS2(double );
#endif // CHAPTER6_H_INCLUDE
练习 6.9 - fact.cc | factMain.cc
编写你自己的 fact.cc 和 factMain.cc ,这两个文件都应该包含上一小节的练习中编写的 Chapter6.h 头文件。通过这些文件,理解你的编译器是如何支持分离式编译的。
解答
fact() 函数定义于 fact.cc 文件中,声明于 Chapter6.h 文件中,并在 factMain.cc 文件中创建 main() 函数实现对 fact() 函数的调用。
// fact.cc
#include "Chapter6.h"
using namespace std;
int fact(int val)
{ // return val > 1 ? (val * fact(val-1)) : 1;
if (val == 0)
return 1;
else
return val * fact(val-1);
}
// factMain.cc
#include <iostream>
#include "Chapter6.h"
using namespace std;
int main()
{
int num;
cout << "input a integer to compute factorial: ";
cin >> num;
if (num < 0)
throw runtime_error ("input cannot be a negative number");
cout << "the factorial of " << num << " is " << fact(num) << endl;
system("pause");
return 0;
}
练习 6.10
编写一个函数,使用指针形参交换两个整数的值。 在代码中调用该函数并输出交换后的结果,以此验证函数的正确性。
解答
源程序 - (使用指针形参):
#include <iostream>
using namespace std;
int swap(int *x, int *y)
{
cout << "before swap: " << *x << " " << *y << endl;
int temp = *x; // 注意交换指针所指对象值, 而非交换地址
*x = *y;
*y = temp;
cout << "after swap: " << *x << " " << *y << endl;
}
int main()
{
int a = 1, b = 2;
swap(&a, &b); // 注意传入实参地址, 而非实参对象
cout << "now: " << a << " " << b << endl;
system("pause");
return 0;
}
输出:
before swap: 1 2
after swap: 2 1
now: 2 1
练习 6.11
编写并验证你自己的 reset 函数,使其作用于引用类型的参数。注:reset 即置 0。
解答
#include <iostream>
using namespace std;
int reset(int &i)
{
i = 0;
}
int main()
{
int a = 1;
reset(a); // 注意传入实参地址, 而非实参对象
cout << a << endl;
system("pause");
return 0;
}
练习 6.12
改写 6.2.1 节练习 (对比练习 6.10) 中的程序,使其引用而非指针交换两个整数的值。你觉得哪种方法更易于使用呢?为什么?
解答
源程序 - (使用引用形参替代指针形参):
#include <iostream>
using namespace std;
int swap(int &x, int &y)
{
cout << "before swap: " << x << " " << y << endl;
int temp = x;
x = y;
y = temp;
cout << "after swap: " << x << " " << y << endl;
}
int main()
{
int a = 1, b = 2;
swap(a, b);
cout << "now: " << a << " " << b << endl;
system("pause");
return 0;
}
输出:
before swap: 1 2
after swap: 2 1
now: 2 1
可见,使用引用形参要比指针形参更具简洁性、易用性和可读性,例如函数定义和函数调用需要注意的细节更少了,无需额外声明指针变量,也避免了拷贝指针的值。
练习 6.13
假设 T 是某种类型的名字,说明以下两个函数声明的区别: 一个是 void f(T),另一个是 void f(&T)。
解答
练习 6.14
举一个形参应该是引用类型的例子,再举一个形参不能是引用类型的例子。
解答
练习 6.15
说明 find_char 函数中的三个形参为什么是现在的类型,特别说明为什么 s 是常量引用而 occurs 是普通引用? 为什么 s 和 occurs 是引用类型而 c 不是? 如果令 s 是普通引用会发生什么情况? 如果令 occurs 是常量引用会发生什么情况?
解答
练习 6.16
下面的这个函数虽然合法,但是不算特别有用。指出它的局限性并设法改善。
bool is_empty(string& s) { return s.empty(); }
解答
is_empty 函数的形参 s 使用了 string & 类型,使之 只能接受 string 对象作为实参。如果下面这样调用是非法的:
const string str = "hello;
bool flag = is_empty(str); // 非法
bool flag = is_empty("hello"); // 非法
若改为 const string & 类型,则更具泛化性,可接受 const string 对象、string 对象、字面值 乃至 其他需要类型转换的对象。如下所示:
bool is_empty(const string& s) { return s.empty(); }
练习 6.17
编写一个函数,判断 string 对象中是否含有大写字母。 编写另一个函数,把 string 对象全部改写成小写形式。 在这两个函数中你使用的形参类型相同吗?为什么?
解答
源程序:
#include <iostream>
#include <string>
using namespace std;
bool has_upper(const string &str) // 常量引用形参 - 参数值只读
{
for (auto c : str) {
if (isupper(c))
return true;
}
return false;
}
void upper_to_lower(string &str) { // 非常量引用形参 - 参数值读写
for (auto &c : str) {
if (isupper(c))
c = tolower(c);
}
}
int main()
{
// 朴素的交互测试
string str;
cin >> str;
cout << has_upper(str) << endl;
upper_to_lower(str);
cout << str << endl;
system("pause");
return 0;
}
控制台交互:
String
1
string
练习 6.18
为下面的函数编写函数声明,从给定的名字中推测函数具备的功能。
(a) 名为 compare 的函数,返回布尔值,两个参数都是 matrix 类的引用。 (b) 名为 change_val 的函数,返回 vector 的迭代器,有两个参数:一个是 int,另一个是 vector 的迭代器。
解答
// 函数声明别忘了分号
(a) bool compare(const matrix &x, const matrix &y);
(b) vector<int>::iterator change_val(int, vector<int>::iterator); // 更难些
练习 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):非法,实参数量与形参列表包含的形参数量不匹配;
- (b):合法,字面值常量可以作为常量引用形参的值;
- (c):合法,调用函数时会发生隐式类型转换;
- (d):合法,调用函数时会发生隐式类型转换。
练习 6.20
引用形参什么时候应该是常量引用?如果形参应该是常量引用,而我们将其设为了普通引用,会发生什么情况?
解答
练习 6.21
编写一个函数,令其接受两个参数:一个是 int 型的数,另一个是 int 指针。 函数比较 int 的值和指针所指的值,返回较大的那个。 在该函数中指针的类型应该是什么?
解答
由题可知,函数实际上比较的是第一个实参的值和第二个实参所指对象的值。因为两个参数的内容都不会被修改 (只读),所有指针类型应为 const int *。
源程序:
#include <iostream>
using namespace std;
int larger_int(const int x, const int *y_ptr)
{
int y = *y_ptr;
return (x > y) ? x : y;
}
int main()
{
// 朴素的交互测试
int a, b;
cin >> a >> b;
cout << "the larger integer is: " << larger_int(a, &b) << endl;
system("pause");
return 0;
}
控制台交互:
9 5
the larger integer is: 9
练习 6.22
编写一个函数,令其交换两个 int 指针。
解答
源程序 (分别交换 指针所指对象的值 和 指针的值):
#include <iostream>
using namespace std;
// 交换指针所指对象的值
void swap_ptr_value(int *x_ptr, int *y_ptr)
{
int temp = *x_ptr;
*x_ptr = *y_ptr;
*y_ptr = temp;
}
// 交换指针自身的值, 即指针地址
void swap_ptr_address(int *(&x_ptr), int *(&y_ptr)) // 即便是指针, 要改变值还是要引用传值
{
int *temp = x_ptr;
x_ptr = y_ptr;
y_ptr = temp;
}
int main()
{
int a = 2, b = 3;
int *a_ptr = &a, *b_ptr = &b; // 指针
cout << "before swap value: " << a << " " << b << endl;
swap_ptr_value(a_ptr, b_ptr);
cout << "after swap value: " << a << " " << b << endl;
cout << "before swap address: " << a_ptr << " " << b_ptr << endl;
swap_ptr_address(a_ptr, b_ptr);
cout << "after swap address: " << a_ptr << " " << b_ptr << endl;
system("pause");
return 0;
}
输出:
before swap value: 2 3
after swap value: 3 2
before swap address: 0x61fe3c 0x61fe38
after swap address: 0x61fe38 0x61fe3c
练习 6.23
参考本节介绍的几个 print 函数,根据理解编写你自己的版本。 依次调用每个函数使其输入下面定义的 i 和 j:
int i = 0, j[2] = { 0, 1 };
解答
源程序:
#include <iostream>
using namespace std;
// 参数是常量整型指针
void print1(const int *p)
{
cout << *p << endl;
}
// 参数分别是常量整型指针和数组容量
void print2(const int *p, const int sz)
{
for(auto i = 0; i != sz; ++i)
cout << *p++ << " ";
cout << endl;
}
// 参数分别是常量整型数组的首尾边界
void print3(const int *beg, const int *end)
{
for(auto it = beg; it != end; ++it)
cout << *it << " ";
cout << endl;
}
// 参数分别是常量整型数组(首元素指针)和数组尺寸 (索引/下标)
void print4(const int arr[], size_t sz)
{
for(size_t i = 0; i != sz; ++i)
cout << arr[i] << " ";
cout << endl;
}
int main()
{
int i = 0, j[2] = {0, 1};
print1(&i);
print1(j);
print2(&i, 1);
print2(j, sizeof(j)/sizeof(*j)); // 数组 j 的容量
print3(begin(j), end(j));
print4(j, end(j)-begin(j)); // 数组 j 的容量
system("pause");
return 0;
}
输出:
0
0
0
0 1
0 1
0 1
练习 6.24
描述下面这个函数的行为。如果代码中存在问题,请指出并改正。
void print(const int ia[10]) { for (size_t i = 0; i != 10; ++i) cout << ia[i] << endl; }
解答
上述函数通过索引/下标依次输出整型常量数组 ia 各元素。但是,for 循环控制结构中,循环条件所使用的字面值 10 与实际输入数组的容量不一定一致。可以增加一个显式表示数组大小的形参 sz:
void print(const int ia[10], const int sz)
{
for (size_t i = 0; i != sz; ++i)
cout << ia[i] << endl;
}
练习 6.25
编写一个 main 函数,令其接受两个实参。把实参的内容连接成一个 string 对象并输出出来。
解答
源程序 - (命令行参数):
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char **argv)
{
string str;
for (int i = 1; i != argc; ++i) // 可以接受任意数量的实参了
str += string(argv[i]) + " ";
cout << str << endl;
return 0;
}
命令行交互:
./test hello world
hello world
练习 6.26
编写一个程序,使其接受本节所示的选项;输出传递给 main 函数的实参内容。
解答
见 练习 6.25。
练习 6.27
编写一个函数,它的参数是 initializer_list 类型的对象,函数的功能是计算列表中所有元素的和。
解答
源程序:
#include <iostream>
using namespace std;
int compute_sum(initializer_list<int> nums)
{
int sum = 0;
for (auto n : nums)
sum += n;
return sum;
}
int main()
{
auto int_list = {1, 2, 3, 4, 5};
cout << "the sum is: " << compute_sum(int_list) << endl;
cout << "the sum is: " << compute_sum({6, 7, 8, 9, 10}) << endl;
system("pause");
return 0;
}
输出:
the sum is: 15
the sum is: 40
练习 6.28
在 error_msg 函数的第二个版本中包含 ErrCode 类型的参数,其中循环内的 elem 是什么类型?
解答
Initializer_list<string> 中所有元素都是 string 类型的,因此 const auto &elem : i1 推断得到的 elem 类型是 const string & 。使用引用是为了避免拷贝长字符串,把它定义为常量的原因是只需要读取字符串的内容而无需修改它 (只读即可,无需读写)。
练习 6.29
在范围 for 循环中使用 initializer_list 对象时,应该将循环控制变量声明成引用类型吗?为什么?
解答
练习 6.30
在编译第 200 页的 str_subrange 函数,看看你的编译器是如何处理函数中的错误的。
解答
编译错误信息:
test.cpp:16:7: error: return-statement with no value, in function returning ‘bool’ [-fpermissive]
练习 6.31
什么情况下返回的引用无效?什么情况下返回常量的引用无效?
解答
练习 6.32
下面的函数合法吗?如果合法,说明其功能;如果不合法,修改其中的错误并解释原因。
int &get(int *array, int index) { return array[index]; } int main() { int ia[10]; for (int i = 0; i != 10; ++i) get(ia, i) = i; }
解答
练习 6.33
编写一个递归函数,输出 vector 对象的内容。
解答
源程序 - 方式一 (迭代器):
#include <iostream>
#include <vector>
using namespace std;
// 注意迭代器形参类型, 此处使用了常量迭代器类型
void print_vector(vector<int>::const_iterator beg, vector<int>::const_iterator end)
{
if (beg != end) {
cout << *beg << " ";
print_vector(++beg, end);
}
}
int main()
{
vector<int> vec = {1, 2, 3, 4, 5};
print_vector(vec.cbegin(), vec.cend()); // 常量迭代器类型
cout << endl;
system("pause");
return 0;
}
源程序 - 方式二 (索引/下标):
#include <iostream>
#include <vector>
using namespace std;
// 使用数组及其当前元素索引作为形参
void print_vector(vector<int> vInt, unsigned index)
{
if (!vInt.empty() && index < vInt.size()) {
cout << vInt[index] << " ";
print_vector(vInt, index+1);
}
}
int main()
{
vector<int> vec = {1, 2, 3, 4, 5};
print_vector(vec, 0);
cout << endl;
system("pause");
return 0;
}
输出:
1 2 3 4 5
练习 6.34
如果 factorial 函数的停止条件如下所示,将发生什么?
if (val != 0)
解答
若输入 val 为非负整数,则正常、正确输出;
若输入为负整数,则程序将因始终不满足终止条件而陷入无限递归,直至溢出。
练习 6.35
在调用 factorial 函数时,为什么我们传入的值是 val-1 而非 val-- ?
解答
若改为 val--,变量的递减操作和传值操作将共存于一条表达式中,可能导致产生未定义的值;换言之,将会永远传入相同的值来递归调用函数,递归将无限执行。
练习 6.36
编写一个函数声明,使其返回数组的引用并且该数组包含 10 个 string 对象。不用使用尾置返回类型、decltype 或者类型别名。
解答
string (&func())[10];
练习 6.37
为上一题的函数再写三个声明,一个使用类型别名,另一个使用尾置返回类型,最后一个使用 decltype 关键字。 你觉得哪种形式最好?为什么?
解答
我觉得尾置返回类型最好,因为它最简洁。
typedef string str_arr[10];
str_arr& fun(); // 类型别名
auto fun() -> string(&)[10]; // 尾置返回类型
string str_arr[10];
decltype(str_arr) &fun(); // decltype 关键字
练习 6.38
修改 arrPtr 函数,使其返回数组的引用。
解答
int odd[] = {1, 3, 5, 7, 9};
int even[] = {2, 4, 6, 8, 10};
// 返回一个引用, 该引用所引的对象是一个含有 5 个整数的数组
decltype(odd)& arrPtr(int i)
{
return (i % 2) ? odd : even; // 返回数组的引用
}
练习 6.39
说明在下面的每组声明中第二条语句是何含义。 如果有非法的声明,请指出来。
(a) int calc(int, int); int calc(const int, const int); (b) int get(); double get(); (c) int *reset(int *); double *reset(double *);
解答
练习 6.40
下面的哪个声明是错误的?为什么?
(a) int ff(int a, int b = 0, int c = 0); (b) char *init(int ht = 24, int wd, char bckgrnd);
解答
声明 (b) 是错误的,C++ 规定 某一形参被赋予了默认实参,则其后面的形参都必须有默认实参。这一规定是为了 防范可能出现的二义性,显然 (b) 违法了该规定。
练习 6.41
下面的哪个调用是非法的?为什么?哪个调用虽然合法但显然与程序员的初衷不符?为什么?
char *init(int ht, int wd = 80, char bckgrnd = ' '); (a) init(); (b) init(24,10); (c) init(14,'*');
解答
练习 6.42
给 make_plural 函数的第二个形参赋予默认实参 's',利用新版本的函数输出单词 success 和 failure 的单数和复数形式。
解答
源程序:
#include <iostream>
#include <string>
using namespace std;
string make_plural(size_t ctr, const string& word, const string& ending = "s")
{
return (ctr > 1) ? word + ending : word;
}
int main()
{
cout << "single: " << make_plural(1, "success", "es") << " "
<< make_plural(1, "failure") << endl;
cout << "plural : " << make_plural(2, "success", "es") << " "
<< make_plural(2, "failure") << endl;
system("pause");
return 0;
}
练习 6.43
你会把下面的哪个声明和定义放在头文件中?哪个放在源文件中?为什么?
(a) inline bool eq(const BigInt&, const BigInt&) {...} (b) void putValues(int *arr, int size);
解答
我会把它们都放进头文件中,其中 (a) 是内联函数,(b) 是函数声明。
练习 6.44
将 6.2.2 节的 isShorter 函数改写成内联函数。
解答
inline bool is_shorter(const string &lft, const string &rht)
{
return lft.size() < rht.size();
}
练习 6.45
回顾在前面的练习中你编写的那些函数,它们应该是内联函数吗? 如果是,将它们改写成内联函数;如果不是,说明原因。
解答
练习 6.46
能把 isShorter 函数定义成 constexpr 函数吗? 如果能,将它改写成 constxpre 函数;如果不能,说明原因。
解答
不能。constexpr 函数指的是能用于常量表达式的函数,其返回值类型及所有形参都要求是字面值类型,而且函数体中必须有且只有一条 return 语句。
练习 6.47
改写 6.3.2 节练习中使用递归输出 vector 内容的程序,使其有条件地输出与执行过程有关的信息。例如,每次调用时输出 vector 对象的大小。分别在打开和关闭调试器的情况下编译并执行这个程序。
解答
源程序:
#include <iostream>
#include <vector>
using namespace std;
// 使用数组及其当前元素索引作为形参, 通过递归函数输出 vector<int> 的内容
void print_vec(vector<int> vec, unsigned index)
{
// 设置在此处输出调试信息
#ifndef NDEBUG
cout << "vector size: " << vec.size() << endl;
#endif // NDEBUG
if (!vec.empty() && index < vec.size())
{
cout << vec[index] << endl;
print_vec(vec, index+1);
}
}
int main()
{
vector<int> vec = {1, 3, 5, 7, 9, 11, 13, 15};
print_vec(vec, 0);
cout << endl;
system("pause");
return 0;
}
练习 6.48
说明下面这个循环的含义,它对 assert 的使用合理吗?
string s; while (cin >> s && s != sought) { } //空函数体 assert(cin);
解答
不合理。从这个程序的意图来看,应该用:
assert(s == sought);
练习 6.49
什么是候选函数?什么是可行函数?
解答
- 候选函数 (candidate function):与被调用函数同名,且其声明在调用点可见。
- 可行函数 (viable function):形参与实参数量相等,且每个实参类型与对应形参类型相同或能转换成形参的类型。
练习 6.50
已知有第 217 页对函数 f 的声明,对于下面的每一个调用列出可行函数。 其中哪个函数是最佳匹配? 如果调用不合法,是因为没有可匹配的函数还是因为调用具有二义性?
(a) f(2.56, 42) (b) f(42) (c) f(42, 0) (d) f(2.56, 3.14)
解答
练习 6.51
编写函数 f 的 4 版本,令其各输出一条可以区分的消息。验证上一个练习的答案,如果你的回答错了,反复研究本节内容直到你弄清自己错在何处。
解答
源程序:
#include <iostream>
using namespace std;
void f()
{
cout << "f()" << endl;
}
void f(int)
{
cout << "f(int)" << endl;
}
void f(int, int)
{
cout << "f(int, int)" << endl;
}
void f(double, double)
{
cout << "f(double, double)" << endl;
}
int main()
{
//f(2.56, 42); // error: 'f' is ambiguous.
f(42);
f(42, 0);
f(2.56, 3.14);
system("pause");
return 0;
}
输出:
f(int)
f(int, int)
f(double, double)
练习 6.52
已知有如下声明:
void manip(int, int); double dobj;
请指出下列调用中每个类型转换的等级。
(a) manip('a', 'z'); (b) manip(55.4, dobj);
解答
- (a) 第 3 级。类型提升实现的匹配 (char 实参自动提升为 int)。
- (b) 第 4 级。算术类型转换实现的匹配 (double 实参自动转换为 int)。
练习 6.53
说明下列每组声明中的第二条语句会产生什么影响,并指出哪些不合法(如果有的话)。
(a) int calc(int&, int&); int calc(const int&, const int&); (b) int calc(char*, char*); int calc(const char*, const char*); (c) int calc(char*, char*); int calc(char* const, char* const);
解答
(c) 不合法。顶层 const 不影响传入函数的对象。
练习 6.54
编写函数的声明,令其接受两个 int 形参并返回类型也是 int;然后声明一个 vector 对象,令其元素是指向该函数的指针。
解答
int func(int, int);
vector<decltype(func)*> ptr; // 要点
练习 6.55
编写 4 个函数,分别对两个int值执行加、减、乘、除运算;在上一题创建的 vector 对象中保存指向这些函数的指针。
解答
#include <iostream>
#include <vector>
using namespace std;
int add(int a, int b)
{
return a + b;
}
int sub(int a, int b)
{
return a - b;
}
int mul(int a, int b)
{
return a * b;
}
int div(int a, int b)
{
return b != 0 ? a / b : 0;
}
int main()
{
decltype(add) *ptr1 = add, *ptr2 = sub, *ptr3 = mul, *ptr4 = div;
vector<decltype(add)*> ptr = {ptr1, ptr2, ptr3, ptr4};
system("pause");
return 0;
}
练习 6.56
调用上述 vector 对象中的每个元素并输出结果
解答
源程序:
#include <iostream>
#include <vector>
using namespace std;
int add(int a, int b)
{
return a + b;
}
int sub(int a, int b)
{
return a - b;
}
int mul(int a, int b)
{
return a * b;
}
int divi(int a, int b)
{
return b != 0 ? a / b : 0;
}
int main()
{
decltype(add) *ptr1 = add, *ptr2 = sub, *ptr3 = mul, *ptr4 = divi;
vector<decltype(add)*> func = {ptr1, ptr2, ptr3, ptr4};
for (auto p : func) {
cout << p(4, 2) << endl;
}
system("pause");
return 0;
}
输出:
6
2
8
2