第六章 函数

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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

6.8

1     int fact(int n);
Chapter6.h

 

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 }
fact.cpp
 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 }
factMain.cpp

 

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 }
View Code

 

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 }
View Code

 

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 << "存在大写字母!\n";
36     else    cout << "没有大写字母!\n"; 
37     cout << s1 << endl;
38     return 0;
39 }
View Code

使用的形参并不相同,对于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 }
View Code

 

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 }  
View Code

注意:要让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 }  
View Code

 

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 }  
View Code

 

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 }  
View Code

我在编译器上跑了一下,得出的结果是合法的。

但是我认为它那个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 }
View Code

 

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 }  
View Code

 

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(形参); 
View Code

第二种方式比较好,既然是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 }
View Code

 

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 }
View Code 

 

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 }
View Code

关闭调试器(即定义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; 
}
View Code

补充:使用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 }
View Code

注:我们上面的代码最后让“不能发生的条件”(即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 }
View Code

 

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 }
View Code

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2017-10-12 21:45  GGBeng  阅读(597)  评论(0编辑  收藏  举报