6.1
形参:与实参有联系的变量,可以是实参的拷贝、引用等。
实参:传递给被调用函数的参数,让调用函数中的值可以给被调用函数使用
6.4
1 #include <iostream> 2 #include <vector> 3 #include <cctype> 4 #include <iterator> 5 #include <stdexcept> 6 #include <string> 7 #include <cstring> 8 9 using std::cin; 10 using std::cout; 11 using std::endl; 12 using std::vector; 13 using std::string; 14 using std::runtime_error; 15 16 int fact(int n) 17 { 18 if (n < 1) return -1; 19 int ans = 1; 20 for (int i = n; i > 0; i--) { 21 ans *= i; 22 } 23 return ans; 24 } 25 26 int main() 27 { 28 int n; 29 while(cin >> n) { 30 cout << fact(n) << endl; 31 } 32 return 0; 33 }
6.5
1 #include <iostream> 2 #include <vector> 3 #include <cctype> 4 #include <iterator> 5 #include <stdexcept> 6 #include <string> 7 #include <cstring> 8 9 using std::cin; 10 using std::cout; 11 using std::endl; 12 using std::vector; 13 using std::string; 14 using std::runtime_error; 15 16 int i_abs(int n) 17 { 18 return n > 0 ? n : -n; 19 } 20 21 int main() 22 { 23 int a; 24 while(cin >> a) 25 cout << i_abs(a) << endl; 26 return 0; 27 }
6.6
形参:生命周期和函数一样
局部变量:生命周期自其定义语句开始至定义所在的块末尾
局部静态变量:生命周期自其定义语句开始至程序结束
6.7
1 #include <iostream> 2 #include <vector> 3 #include <cctype> 4 #include <iterator> 5 #include <stdexcept> 6 #include <string> 7 #include <cstring> 8 9 using std::cin; 10 using std::cout; 11 using std::endl; 12 using std::vector; 13 using std::string; 14 using std::runtime_error; 15 16 int coco() 17 { 18 static int flag = 0; 19 if (!flag) return flag++; 20 return 1; //flag的值不是0时执行此语句 21 } 22 23 int main() 24 { 25 for (int i = 1; i <= 10; i++) 26 cout << coco() << endl; 27 return 0; 28 }
6.8
1 int fact(int n);
6.9
1 #include <iostream> 2 #include "Chapter6.h" 3 4 int fact(int n) 5 { 6 int ans = 1; 7 for (int i = n; i != 0; i--) 8 ans *= i; 9 return ans; 10 }
1 #include <iostream> 2 #include "fact.cpp" 3 4 using std::cin; 5 using std::cout; 6 using std::endl; 7 8 int main() 9 { 10 int n; 11 while(cin >> n) 12 cout << fact(n) << endl; 13 return 0; 14 }
6.10
1 #include <iostream> 2 #include <vector> 3 #include <string> 4 5 using std::cin; 6 using std::cout; 7 using std::endl; 8 using std::vector; 9 using std::string; 10 11 void swap(int *p1, int *p2) 12 { 13 int tmp; 14 tmp = *p1; 15 *p1 = *p2; //改变P1所指对象的值 16 *p2 = tmp; 17 } 18 19 int main() 20 { 21 int a, b; 22 while (cin >> a >> b) { 23 cout << "交换前:a = " << a << ", b = " << b << endl; 24 swap(&a, &b); 25 cout << "交换后:a = " << a << ", b = " << b << endl; 26 } 27 return 0; 28 }
6.12
1 #include <iostream> 2 #include <vector> 3 #include <string> 4 5 using std::cin; 6 using std::cout; 7 using std::endl; 8 using std::vector; 9 using std::string; 10 11 void swap(int &r1, int &r2) 12 { 13 int tmp; 14 tmp = r1; 15 r1 = r2; //改变P1所绑定对象的值 16 r2 = tmp; 17 } 18 19 int main() 20 { 21 int a, b; 22 while (cin >> a >> b) { 23 cout << "交换前:a = " << a << ", b = " << b << endl; 24 swap(a, b); 25 cout << "交换后:a = " << a << ", b = " << b << endl; 26 } 27 return 0; 28 }
6.13
void f(T):传值
void f(&T):穿引用
6.15
因为s字符串是不能被函数所修改的,所以是常量引用。c可能是一个临时变量,所以不需要使用引用类型,也无需函数加以修改其本身。如果令occurs为常量引用,则输出occurs为0(不能加以修改),而s可能会在程序中被修改。
6.16
形参被定义成普通的引用,在本题虽然不会引发错误,但这么做的局限性如下:我们不能把const对象、字面值或者需要类型转换的对象传递给这个形参。
6.17
1 #include <iostream> 2 #include <vector> 3 #include <cctype> 4 #include <string> 5 6 using std::cin; 7 using std::cout; 8 using std::endl; 9 using std::vector; 10 using std::string; 11 12 bool fun1(const string &s) 13 { 14 for (auto it = s.begin(); it != s.end(); it++) { 15 if (isupper(*it)) { 16 return true; 17 } 18 } 19 return false; 20 } 21 22 void fun2(string &s) 23 { 24 for (auto &i : s) 25 i = isupper(i) ? tolower(i) : i; 26 } 27 28 int main() 29 { 30 string s1; 31 cin >> s1; 32 cout << s1 << endl; 33 bool ownUpper = fun1(s1); 34 fun2(s1); 35 if (ownUpper) cout << "存在大写字母! "; 36 else cout << "没有大写字母! "; 37 cout << s1 << endl; 38 return 0; 39 }
使用的形参并不相同,对于fun1,我们不需要修改对象的值,所以可以使用常量引用;而对于fun2,我们需要修改对象的值,所以不能使用常量引用。
6.18
(a):bool compare(matrix &, matrix &);
(b):vector<int>::iterator change_val(int, vector<int>::iterator);
6.20
引用形参什么时候是常量引用:首先函数内不要修改所引用对象的值时,其次我们希望能够使用const对象、字面值或需要类型转换的对象作为实参时。
形参本应该是常量引用,而我们将其设为了普通引用:可能误导用户能够修改其中的值;还可能因为一些只能够用于常量引用的实参,从而导致编译器报错。
6.22
1 #include <iostream> 2 #include <vector> 3 #include <cctype> 4 #include <string> 5 6 using std::cin; 7 using std::cout; 8 using std::endl; 9 using std::vector; 10 using std::string; 11 12 void swap_point(int *&p, int *&q) //这个形参类型可以的 13 { 14 int *s = nullptr; 15 s = p; 16 p = q; 17 q = s; 18 } 19 20 int main() 21 { 22 int a = 3, b = 4; 23 int *p1 = &a, *p2 = &b; 24 cout << "交换指针的值之前:p1的值为" << p1 << ",p2的值为" << p2 << endl; 25 swap_point(p1, p2); 26 cout << "交换指针的值之后:p1的值为" << p1 << ",p2的值为" << p2 << endl; 27 return 0; 28 }
6.25
1 #include <iostream> 2 #include <vector> 3 #include <cctype> 4 #include <string> 5 6 using std::cin; 7 using std::cout; 8 using std::endl; 9 using std::vector; 10 using std::string; 11 12 13 int main(int argc, char *argv[]) //形参argv是一个数组,它的元素是指向C风格字符串的指针 14 { 15 string ss; 16 for (int i = 1; i != argc; ++i) { 17 ss += argv[i]; 18 ss += " "; 19 } 20 cout << ss <<endl; 21 return 0; 22 }
注意:要让main函数接受参数,我们可以在linux命令行界面输入参数。
6.26
1 #include <iostream> 2 #include <vector> 3 #include <cctype> 4 #include <string> 5 6 using std::cin; 7 using std::cout; 8 using std::endl; 9 using std::vector; 10 using std::string; 11 12 13 int main(int argc, char *argv[]) //形参argv是一个数组,它的元素是指向C风格字符串的指针 14 { 15 for (int i = 1; i != argc; ++i) { 16 cout << argv[i] << endl; 17 } 18 return 0; 19 }
6.27
1 #include <iostream> 2 #include <vector> 3 #include <cctype> 4 #include <string> 5 #include <iterator> 6 #include <initializer_list> 7 8 using namespace std; 9 10 void print(initializer_list<int> a) 11 { 12 int ans = 0; 13 for (auto i : a) 14 ans += i; 15 cout << ans << endl; 16 } 17 18 int main() 19 { 20 print({1, 2, 3, 4 ,5}); 21 return 0; 22 }
6.30
int cmp(int a, int b) { if (a == b) return; //[Error] return-statement with no value, in function returning 'int' [-fpermissive] if (a > b) return 1; if (a < b) return 0; }
报错信息:[Error] return-statement with no value, in function returning 'int' [-fpermissive]
6.31
返回的引用无效:当返回局部对象的引用时
返回常量的引用无效:当要给调用的结果赋值时,函数的返回类型只能是非常量引用
6.32
书中的代码:
1 #include <iostream> 2 #include <vector> 3 #include <cctype> 4 #include <string> 5 #include <iterator> 6 #include <initializer_list> 7 8 using namespace std; 9 10 int &get(int *array, int index) 11 { 12 return array[index]; 13 } 14 15 int main() 16 { 17 int ia[10]; 18 for (int i = 0; i != 10; i++) 19 get(ia, i) = i; 20 return 0; 21 }
我在编译器上跑了一下,得出的结果是合法的。
但是我认为它那个get函数涉及“返回局部对象的引用”,所以我也写了一个合法的函数:
1 #include <iostream> 2 #include <vector> 3 #include <cctype> 4 #include <string> 5 #include <iterator> 6 #include <initializer_list> 7 8 using namespace std; 9 10 int &get(int (&array)[10], int index) //形参是数组的引用 11 { 12 return array[index]; 13 } 14 15 int main() 16 { 17 int ia[10]; 18 for (int i = 0; i != 10; i++) 19 get(ia, i) = i; 20 // for (auto i : ia) 21 // cout << i << " "; 22 // cout << endl; 23 return 0; 24 }
6.33
1 #include <iostream> 2 #include <vector> 3 #include <cctype> 4 #include <string> 5 #include <iterator> 6 #include <initializer_list> 7 8 using namespace std; 9 10 vector<int> a = {0, 1, 2, 3, 4}; 11 12 void print(vector<int>::iterator iter) 13 { 14 if (iter != a.end()) { 15 cout << *iter++ << endl; 16 print(iter); 17 } 18 return; 19 } 20 21 int main() 22 { 23 auto it = a.begin(); 24 print(it); 25 }
6.34
如果传入的实参是负数,那将陷入无限循环,直至程序栈空间被耗尽。
6.35
val--:会先将自减之前的值拷贝一个副本,然后进行自减运算,再将那个副本作为实参调用函数。
结果:每次传的实参的值都是相同的,无限循环,且与初衷背离。
6.36
string (&func(形参))[10];
6.37
1 //类型别名 2 using arrS = string[10]; 3 arrS& func(形参); 4 //尾置返回类型 5 auto func(形参) -> string(&)[10]; 6 //decltype关键字 7 string ss[10]; 8 decltype(ss) &func(形参);
第二种方式比较好,既然是C++11的新标准,那么肯定有它创新的意义所在,简短方便。
6.38
1 #include <iostream> 2 #include <vector> 3 #include <cctype> 4 #include <string> 5 #include <iterator> 6 #include <initializer_list> 7 8 using namespace std; 9 10 int odd[] = {1, 3, 5, 7, 9}; 11 int even[] = {0, 2, 4, 6, 8}; 12 13 //返回数组的引用 14 decltype(odd) &arrPtr(int i) 15 { 16 return (i % 2) ? odd : even; 17 } 18 19 int main() 20 { 21 cout << arrPtr(3)[1] << endl; //输出3 22 return 0; 23 }
6.39
第二条声明语句的含义:
(a):实参要有两个,每个实参的类型可以是常量整型、整型
(b):无参数传递,返回类型为double
(c):实参为double类型的指针,返回类型为指向int类型的指针
其中有非法声明的组别是:(a)
6.40
(b)是错误的,因为一旦某个形参被赋予了默认值,它后面的所有形参都必须有默认值。
6.41
(a)非法,因为形参ht没有默认值,而(a)调用时却没有提供相应的实参
(c)与初衷不符,因为传递的'*'是个char,而形参wd是int,所以'*'可以转换成形参中的wd的类型,而初衷是将'*'传递给形参bckgrnd。
6.42
1 #include <iostream> 2 #include <vector> 3 #include <cctype> 4 #include <string> 5 #include <iterator> 6 #include <initializer_list> 7 8 using namespace std; 9 10 string make_plural(size_t ctr, const string& word, const string& ending = "s") 11 { 12 return (ctr > 1) ? word+ending : word; 13 } 14 int main() 15 { 16 cout<<"两单词的单数形式:"<<make_plural(1,"success","es")<<" "<<make_plural(1,"failure")<<endl; 17 cout<<"两单词的复数形式:"<<make_plural(2,"success","es")<<" "<<make_plural(2,"failure")<<endl; 18 return 0; 19 }
6.43
(a):放在头文件中,因为它是内联函数
(b):放在头文件中,函数声明最好放在头文件中
6.44
inline bool isShorter(const string &s1, const string &s2)
{
return s1.size() < s2.size();
}
6.46
不能,尽管其形参是常量引用,但是const string并不是字面值类型。
6.47
打开调试器(即未定义NDEBUG):
1 #include <iostream> 2 #include <vector> 3 #include <cctype> 4 #include <string> 5 #include <iterator> 6 #include <initializer_list> 7 #include <cassert> 8 9 //#define NDEBUG 10 11 using namespace std; 12 13 void print(vector<int> vec) 14 { 15 #ifndef NDEBUG 16 cout << "vector size: " << vec.size() << endl; 17 #endif 18 // assert (!vec.empty()); 19 if (vec.size() > 0) { 20 cout << vec.back() << endl; 21 vec.pop_back(); 22 print(vec); 23 } 24 else if(vec.size() == 0) { 25 cout << "vector size is zero, no value." << endl; 26 } 27 } 28 int main() 29 { 30 vector<int> a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 31 print(a); 32 return 0; 33 }
关闭调试器(即定义NDEBUG):
#include <iostream> #include <vector> #include <cctype> #include <string> #include <iterator> #include <initializer_list> #include <cassert> #define NDEBUG //定义NDEBUG using namespace std; void print(vector<int> vec) { #ifndef NDEBUG cout << "vector size: " << vec.size() << endl; #endif // assert (!vec.empty()); if (vec.size() > 0) { cout << vec.back() << endl; vec.pop_back(); print(vec); } else if(vec.size() == 0) { cout << "vector size is zero, no value." << endl; } } int main() { vector<int> a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; print(a); return 0; }
补充:使用assert的代码(应仅用于验证不可能发生的事情,即检查不能发生的条件)
1 #include <iostream> 2 #include <vector> 3 #include <cctype> 4 #include <string> 5 #include <iterator> 6 #include <initializer_list> 7 #include <cassert> 8 9 #define NDEBUG //定义NDEBUG 10 11 using namespace std; 12 13 void print(vector<int> vec) 14 { 15 #ifndef NDEBUG //定义NDEBUG后,下面这条语句将被忽略 16 cout << "vector size: " << vec.size() << endl; 17 #endif 18 assert (!vec.empty()); //当vec为空时(即表达式为假),assert输出错误信息并终止程序的执行 19 cout << vec.back() << endl; 20 vec.pop_back(); 21 print(vec); 22 } 23 int main() 24 { 25 vector<int> a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 26 print(a); 27 return 0; 28 }
注:我们上面的代码最后让“不能发生的条件”(即vec.empty==true)发生了,此时会终止程序的执行。
6.48
不合理,只要有输入,则assert一直为真,无意义。assert最好用于检查不能发生的条件。
可以替换为:
assert(s == sought);
6.49
候选函数:一次调用对应的重载函数集中的函数,它①与被调用的函数同名,②声明在调用点可见
可行函数:此时考察本次调用提供的实参,在候选函数中能被这组实参调用的函数
6.50
只有(a)不合法,因为该调用具有二义性。
6.52
(a):等级3,为通过类型提升实现的匹配
(b):等级4,为通过算术类型转换实现的匹配
6.53
第二条语句产生的影响
(a):实参若是常量,则调用第二条语句
(b):同上
(c):顶层const,函数调用时会忽略之,区别仅仅是调用第二个函数时不能写值
所以非法的是(c)
6.54
int func(int, int ); //函数的声明
typedef decltype(func) *pfunc; //pfunc为指向函数的指针
vector<pfunc> vec;
6.55
1 #include <iostream> 2 #include <vector> 3 #include <cctype> 4 #include <string> 5 #include <iterator> 6 #include <initializer_list> 7 #include <cassert> 8 9 using namespace std; 10 11 int fun1(int a, int b) 12 { 13 return a + b; 14 } 15 16 int fun2(int a, int b) 17 { 18 return a - b; 19 } 20 21 int fun3(int a, int b) 22 { 23 return a * b; 24 } 25 26 int fun4(int a, int b) 27 { 28 return a / b; 29 } 30 31 int func(int, int ); //函数的声明 32 typedef decltype(func) *pfunc; //pfunc为指向函数的指针 33 vector<pfunc> vec; 34 35 int main() 36 { 37 vec.push_back(fun1); 38 vec.push_back(fun2); 39 vec.push_back(fun3); 40 vec.push_back(fun4); 41 cout << vec[1](3,2) << endl; //3-2=1 42 return 0; 43 }
6.56
1 #include <iostream> 2 #include <vector> 3 #include <cctype> 4 #include <string> 5 #include <iterator> 6 #include <initializer_list> 7 #include <cassert> 8 9 using namespace std; 10 11 int fun1(int a, int b) 12 { 13 return a + b; 14 } 15 16 int fun2(int a, int b) 17 { 18 return a - b; 19 } 20 21 int fun3(int a, int b) 22 { 23 return a * b; 24 } 25 26 int fun4(int a, int b) 27 { 28 return a / b; 29 } 30 31 int func(int, int ); //函数的声明 32 typedef decltype(func) *pfunc; //pfunc为指向函数的指针 33 vector<pfunc> vec; 34 35 int main() 36 { 37 vec.push_back(fun1); 38 vec.push_back(fun2); 39 vec.push_back(fun3); 40 vec.push_back(fun4); 41 for (auto function : vec) 42 cout << function(3, 2) << endl; 43 return 0; 44 }