C++基础知识07

第七章:函数探幽

内联函数

内联函数是C++为提高程序运行速度所做的一项改进。常规函数和内联函数之间的主要区别不在于编写方式,而在于C++编译器如何将它们组合到程序中。内联函数的编译代码与其他程序代码“内联”起来了。也就是说,编译器将使用相应的函数代码替换函数调用。对于内联代码,程序无需跳到另一个位置处执行代码,再跳回来。因此,内联函数的运行速度比常规函数稍快,但代价是需要占用更多内存。

内联函数

使用:

  • 在函数声明前加上关键字inline;
  • 在函数定义前加上关键字inline。

程序员请求将函数作为内联函数时,编译器并不一定会满足这种要求。它可能认为该函数过大或注意到函数调用了自己(内联函数不能递归),因此不将其作为内联函数;而有些编译器没有启用或实现这种特性。

引用变量

C++新增了一种复合类型——引用变量。引用是已定义的变量的别名(另一个名称),引用变量的主要用途是用作函数的形参。通过将引用变量用作参数,函数将使用原始数据,而不是其副本。这样除指针之外,引用也为函数处理大型结构提供了一种非常方便的途径,同时对于设计类来说,引用也是必不可少的。

创建引用变量

C和C++使用&符号来指示变量的地址。C++给&符号赋予了另一个含义,将其用来声明引用。

“int a=10; int & rodents =a;” &不是地址运算符,而是将rodents的类型声明为int &,即指向int变量的引用,引用声明允许将a和rodents互换,它们指向相同的值和内存单元

int pt =&a; 这是指向a的指针,rodents 和pt都可以和a互换,表达式&rodents和pt都可以和&a互换。引用和指针在表示方法不同,必须在声明引用时将其初始化,不能像执政一样,先声明在初始化(int a; int &yy; yy=a; //错误)。

引用接近const指针,必须在创建时初始化,并且不能改变

int & rodents =a; //引用 int * const pr = &a; //伪指针表示

将引用作为函数参数

引用经常被用作函数参数,使得函数中的变量名成为调用程序中的变量的别名。这种传递参数的方法称为按引用传递。按引用传递允许被调用的函数能够访问调用函数中的变量。

按值/引用传递

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55


void (int &a, int &b); //引用
void swapB(int *p, int *q); //指针
void swapC(int a, int b); //值

int main()
{
using namespace std;
int num1 = 300;
int num2 = 100;
cout << "num1 = $" << num1;
cout << "num2 = $" << num2 << endl;
//使用引用交换
swapA(num1, num2);
cout << "num1 = $" << num1;
cout << "num2 = $" << num2 << endl;
//使用指针进行交换
swapB(&num1, &num2);
cout << "num1 = $" << num1;
cout << "num2 = $" << num2 << endl;
// 使用值 进行交换(不可以修改原始数据,所以失败)
swapC(num1, num2);
cout << "num1 = $" << num1;
cout << "num2 = $" << num2 << endl;
return 0;
}

void (int &a, int &b)
{
int tmp;
tmp = a;
a = b;
b = tmp;
}

void swapB(int *a, int *b)
{
int tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
void swapC(int a, int b)
{
int tmp;
tmp = a;
a = b;
b = tmp;
}
---------------------------------------------
/* 按引用传递和按值传递看起来相同,然而,地址运算符(&)使得按地址传递.
swapA( )中,变量a和b是别名,所以交换a和b的值相当于交换num1,2的值;swapC( )中,变量a和b是复制了num1和num2的值的新变量,因此交换a和b的值并不会影响原值。
swapB()指针版本需要在函数使用p和q的整个过程中使用解除引用运算符*,
*/

引用属性和特别之处

使用引用前面添加关键字const(double xx(const double &ra);) ,当编译器发现修改了ra的值,将生成错误消息。

临时变量、引用参数和const

如果实参与引用参数不匹配,C++将生成临时变量,

如果引用参数是const,则编译器子啊两种情况下生成临时变量(实参的类型正确,但不是左值;实参的类型不正确,但可以转换为正确的类型)左值参数是可被引用的数据对象,例如,变量、数组元素、结构成员、引用和解除引用的指针都是左值。非左值包括字面常量(用引号括起的字符串除外,它们由其地址表示)和包含多项的表达式

C++11新增了另一种引用——右值引用。这种引用可指向右值,是使用&&声明的,新增右值引用的主要目的是,让库设计人员能够提供有些操作的更有效实现.

引用与结构

引入引用主要是为了用于这些类型的,而不是基本的内置类型。

使用结构引用参数的方式与使用基本变量引用相同,只需在声明结构参数时使用引用运算符&即可。如果不希望函数修改传入的结构,可使用const。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124

#include <string>
using namespace std;
//结构体
struct free_throws
{
string name;
int made;
int attempts;
float percent;
};

//函数原型
void show(const free_throws &ft);
void set_pc(free_throws &ft);

free_throws &accumulate(free_throws &target, const free_throws &source);

int main()
{
//初始化了多个结构对象,结构percent未进行初始化 被设置为0
free_throws one = {"Hello World", 13, 14};
free_throws two = {"good mon", 10, 16};
free_throws three = {"Li ming", 7, 9};
free_throws four = {"Han xx", 5, 9};
free_throws five = {"long long", 6, 14};
free_throws team = {"endend", 0, 0};

free_throws dup;
/* et_pc()的形参ft为引用,因此ft指向one,
函数set_pc()的代码设置成员one.percent
也可用指针传递 set_pc(&one) void set_pc(free_throws *pt)
*/
set_pc(one);
/* display()显示结构的内容,而不修改它,因此这个函数使用了一个const引用参数
这个函数可以按值传递,也可以这样引用传递,但引用传递节省时间和内存。 */
show(one);
/* accumulate()接收两个结构参数,
并将第二个结构的成员attempts和made的数据添加到第一个结构的相应成员中
只修改了第一个结构,因此第一个参数为引用,而第二个参数为const引用
*/
accumulate(team, one);
show(team);
/* 将结构对象team作为第一个参数传递给了accumulate(),target指向的是team
数accumulate()修改team,再返回指向它的引用
如果返回类型被声明为free_throws而不是free_throws &,
上述返回语句将返回target(也就是team)的拷贝。
但返回类型为引用,这意味着返回的是最初传递给accumulate()的team对象
接下来,将accumulate()的返回值作为参数传递给了show(),这意味着将team传递给了show()。
show()的参数为引用,这意味着函数show()中的ft指向的是team,因此将显示team的内容
//等同下面:
accumulate(team, two);
show(team);
*/
show(accumulate(team, two));
/* 同上 show(accumulate(team, two));
可以写成:
accumulate(team, three);
accumulate(team, four); */
accumulate(accumulate(team, three), four);
show(team);
//赋值语句,将team赋值到dup
dup = accumulate(team, five);
cout << "show team:n";
show(team);
cout << "show dup after assignment:n";
show(dup);
set_pc(four);

/* 这条语句将值赋给函数调用,这是可行的,因为函数的返回值是一个引用。
如果函数accumulate()按值返回,这条语句将不能通过编译。
由于返回的是指向dup的引用,因此上述代码与下面的代码等效
accumulate(dup, five);
dup=four;
其中第二条语句消除了第一条语句所做的工作,
因此在原始赋值语句使用accumulate()的方式并不好 */
accumulate(dup, five) = four;
cout << "show dup after ill-advised assignment:n";
show(dup);
return 0;
}

void show(const free_throws &ft)
{
cout << "Name: " << ft.name << 'n';
cout << "Made: " << ft.made << 't';
cout << "Attempts: " << ft.attempts << 't';
cout << "Percent: " << ft.percent << 'n';
}

void set_pc(free_throws &ft)
{
if (ft.attempts != 0)
ft.percent = 100.0f * float(ft.made) / float(ft.attempts);
else
ft.percent = 0;
}

free_throws &accumulate(free_throws &target, const free_throws &source)
{
target.attempts += source.attempts;
target.made += source.made;
set_pc(target);
return target;
}
/*
Name: Hello World
Made: 13 Attempts: 14 Percent: 92.8571
Name: endend
Made: 13 Attempts: 14 Percent: 92.8571
Name: endend
Made: 23 Attempts: 30 Percent: 76.6667
Name: endend
Made: 35 Attempts: 48 Percent: 72.9167
show team:
Name: endend
Made: 41 Attempts: 62 Percent: 66.129
show dup after assignment:
Name: endend
Made: 41 Attempts: 62 Percent: 66.129
show dup after ill-advised assignment:
Name: Han xx
Made: 5 Attempts: 9 Percent: 55.5556
*/

探究程序

返回引用与传统返回机制的不同之处:

传统返回机制与按值传递函数参数类似:计算关键字return后面的表达式,并将结果返回给调用函数。从概念上说,这个值被复制到一个临时位置,而调用程序将使用这个值。如果accumulate()返回一个结构,而不是指向结构的引用,将把整个结构复制到一个临时位置,再将这个拷贝复制给dup。但在返回值为引用时,将直接把team复制到dup,其效率更高。

返回引用时最重要的一点是,应避免返回函数终止时不再存在的内存单元引用。为避免这种问题,最简单的方法是,返回一个作为参数传递给函数的引用。作为参数的引用将指向调用函数使用的数据,因此返回的引用也将指向这些数据。另一种方法是用new来分配新的存储空间。前面见过这样的函数,它使用new为字符串分配内存空间,并返回指向该内存空间的指针。注意:在不再需要new分配的内存时,应使用delete来释放它们。调用clone( )隐藏了对new的调用,这使得以后很容易忘记使用delete来释放内存。

将const用于引用返回类型:假设您要使用引用返回值,但又不允许执行像给accumulate()赋值这样的操作,只需将返回类型声明为const引用,现在返回类型为const,是不可修改的左值。

将引用用于类对象

将类对象传递给函数时,C++通常的做法是使用引用(函数将类string、ostream、istream、ofstream和ifstream等类的对象作为参数)。

对象继承和引用

ofstream对象可以使用ostream类的方法,这使得文件输入/输出的格式与控制台输入/输出相同。使得能够将特性从一个类传递给另一个类的语言特性被称为继承。简单地说,ostream是基类(因为ofstream是建立在它的基础之上的),而ofstream是派生类(因为它是从ostream派生而来的)。派生类继承了基类的方法,这意味着ofstream对象可以使用基类的特性,如格式化方法precision( )和setf( )。继承的另一个特征是,基类引用可以指向派生类对象,而无需进行强制类型转换。这种特征的一个实际结果是,可以定义一个接受基类引用作为参数的函数,调用该函数时,可以将基类对象作为参数,也可以将派生类对象作为参数。例如,参数类型为ostream &的函数可以接受ostream对象(如cout)或您声明的ofstream对象作为参数。

使用应用参数

  • 程序员能够修改调用函数中的数据对象。
  • 通过传递引用而不是整个数据对象,可以提高程序的运行速度

当数据对象较大时(如结构和类对象),第二个原因最重要。这些也是使用指针参数的原因。

对于使用传递的值而不作修改的函数:

  • 果数据对象很小,如内置数据类型或小型结构,则按值传递。
  • 如果数据对象是数组,则使用指针,因为这是唯一的选择,并将指针声明为指向const的指针。
  • 如果数据对象是较大的结构,则使用const指针或const引用,以提高程序的效率。这样可以节省复制结构所需的时间和空间。
  • 如果数据对象是类对象,则使用const引用。类设计的语义常常要求使用引用,这是C++新增这项特性的主要原因。因此,传递类对象参数的标准方式是按引用传递。

对于修改调用函数中数据的函数:

  • 如果数据对象是内置数据类型,则使用指针。如果看到诸如fixit(&x)这样的代码(其中x是int),则很明显,该函数将修改x。
  • 如果数据对象是数组,则只能使用指针。
  • 如果数据对象是结构,则使用引用或指针
  • 如果数据对象是类对象,则使用引用

默认参数

默认参数指的是当函数调用中省略了实参时自动使用的一个值(缺省值),这极大地提高了使用函数的灵活性。

设置默认值必须通过函数原型。 char left(const char str, int n = 1); //n=1

对于带参数列表的函数,必须从右向左添加默认值。也就是说,要为某个参数设置默认值,则必须为它右边的所有参数提供默认值

int fun1 (int n =1, int m, int j =5) //错误

int fun2( int n, int m=1, int j=5) //可以

函数重载

函数多态是C++在C语言的基础上新增的功能。默认参数让您能够使用不同数目的参数调用同一个函数,而函数多态(函数重载)让您能够使用多个同名的函数。术语“多态”指的是有多种形式,因此函数多态允许函数可以有多种形式。类似地,术语“函数重载”指的是可以有多个同名的函数,因此对名称进行了重载。

函数重载的关键是函数的参数列表——也称为函数特征标。如果两个函数的参数数目和类型相同,同时参数的排列顺序也相同,则它们的特征标相同,而变量名是无关紧要的。C++允许定义名称相同的函数,条件是它们的特征标不同。如果参数数目和/或参数类型不同,则特征标也不同,例如print函数。

注意: int fun(int x) 和 int fun(int & x),不是重载, 译器在检查函数特征标时,将把类型引用和类型本身视为同一个特征标。重载也不区分const。是特征标,而不是函数类型使得可以对函数进行重载。

虽然函数重载很吸引人,但也不要滥用。仅当函数基本上执行相同的任务,但使用不同形式的数据时,才应采用函数重载。

使用一个带默认参数的函数要简单些。只需编写一个函数(而不是两个函数),程序也只需为一个函数(而不是两个)请求内存;需要修改函数时,只需修改一个。然而,如果需要使用不同类型的参数,则默认参数便不管用了,在这种情况下,应该使用函数重载。

函数模版

C++编译器实现了C++新增的一项特性——函数模板。函数模板是通用的函数描述,也就是说,它们使用泛型来定义函数,其中的泛型可用具体的类型(如int或double)替换。通过将类型作为参数传递给模板,可使编译器生成该类型的函数。由于模板允许以泛型(而不是具体类型)的方式编写程序,因此有时也被称为通用编程。由于类型是用参数表示的,因此模板特性有时也被称为参数化类型。

template //

准C++98添加关键字typename之前,C++使用关键字class

template

重载模版

并非所有的类型都使用相同的算法。为满足这种需求,可以像重载常规函数定义那样重载模板定义。和常规重载一样,被重载的模板的函数特征标必须不同.

template

void Swap(T &a, T &b);

template

void Swap(T ,T b, int n);

实例化和具体化

最初,编译器只能通过隐式实例化,来使用模板生成函数定义,但现在C++还允许显式实例化。可以直接命令编译器创建特定的实例,如Swap( )。其语法是,声明所需的种类——用<>符号指示类型,并在声明前加上关键字template

template void Swap(int, int )

显式具体化使用下面两个等价的声明之一

template <> void Swap (int &, int &);

template <> void Swap(int &, int &);

区别在于,这些声明的意思是“不要使用Swap( )模板来生成函数定义,而应使用专门为int类型显式地定义的函数定义”。这些原型必须有自己的函数定义。显式具体化声明在关键字template后包含<>,而显式实例化没有。

问答

  1. 那种函数适合定义内联函数

一行代码的小型 非递归函数

  1. 函数原”void song(const char * name, int times);”,提供默认值修改

void song(char * name = “Hello”, int times=1)

  1. 编写iquote( )的重载版本——显示其用双引号括起的参数。编写3个版本:一个用于int参数,一个用于double参数,另一个用于string参数。
1
2
3
4
5
6
7
8
9
void iquote(int n){
cout<<"""<<n<<""";
}
void iquote(double x){
cout<<'"'<<x<<'"';
}
void iquote(const char *str){
cout<<"""<<str<<""";
}
  1. 给出一个结构体,编写函数,将box结构因为形参,并显示结构成员值,并且求体积
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct box{
char maker[20];
float height;
float width;
float length;
float volume;
}
//显示成员
void show (const box & container){
cout<<container.make<<endl;
...
}
//计算体积
void Calvolume(box & crate){
create.volume = create.height * create.width * create.length;
}
  1. 指出下面每个目标是否可以使用默认参数或函数重载完成,或者这两种方法都无法完成,并提供合适的原型。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* mass(density, volume)返回密度为density、体积为volume的物体的质量,而mass(denstity)返回密度为density、体积为1.0立方米的物体的质量。这些值的类型都为double。 */
double mass(double d, double v=1.0);
//重载
double mass(double d, double v);
double mass(double d);

/* repeat(10, “I'm OK”)将指定的字符串显示10次,而repeat(“But you're kind of stupid”)将指定的字符串显示5次。 */
void repeat(int times, const char * str);
void repeat(const char *str);

/* average(3, 6)返回两个int参数的平均值(int类型),而average(3.0, 6.0)返回两个double值的平均值(double类型) */
int average(int a, int b);
double average(double x, double y);

/* mangle(“I'm glad to meet you”)根据是将值赋给char变量还是char*变量,分别返回字符I和指向字符串“I'm mad to gleet you”的指针 */
不可以这么做,因为两个版本特征标相同。
  1. 编写返回两个参数中较大值的函数模板
1
2
3
4
template<class T>
T max(T t1, T t2){
return t1>t2 ? t1:t2;
}
  1. 给定问答5的模板和问答4的box结构,提供一个模板具体化,它接受两个box参数,并返回体积较大的一个。
1
2
3
template<> box max(box b1, box b2){
return b1.volume > b2.volume ? b1:b2;
}
  1. 看程序指出v1-v5类型
1
2
3
4
5
6
7
8
9
int g(int x);
...
float m = 5.5f;
float & rm =m;
decltype(m) v1 =m; //float
decltype(rm) v2 =m; //float &
decltype((m)) v3 =m; //float &
decltype(g(100)) v4; // int
decltype(2.0*m) v5; //double

代码

  1. 接受一个参数(字符串的地址),并打印该字符串的函数。然而,如果提供了第二个参数(int类型),且该参数不为0,则该函数打印字符串的次数将为该函数被调用的次数(int 为函数调用次数。)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30


using namespace std;

unsigned k_times = 0;
void print_times(const char *szTmp, int flag = 0)
{
++k_times;
unsigned uPrintfTimes = (0 == flag) ? 1 : k_times;
cout << ">>>>" << endl;
for (unsigned i = 0; i < uPrintfTimes; ++i)
{
cout << szTmp << endl;
}
cout << "<<<<" << endl;
cout << "-----------------" << endl;
}

int main(void)
{
const char *szTxt = "hi, yangyang.gnu";
print_times(szTxt, 8);
print_times(szTxt);
print_times(szTxt, -1);
print_times(szTxt);
print_times(szTxt, 256);

cout << endl;
return (0);
}
  1. CandyBar结构包含3个成员。第一个成员存储candy bar的品牌名称;第二个成员存储candy bar的重量(可能有小数);第三个成员存储candy bar的热量(整数)。请编写一个程序,它使用一个这样的函数,即将CandyBar的引用、char指针、double和int作为参数,并用最后3个值设置相应的结构成员。最后3个参数的默认值分别为“Millennium Munch”、2.85和350。另外,该程序还包含一个以CandyBar的引用为参数,并显示结构内容的函数。请尽可能使用const.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34


using namespace std;

struct TCandyBar
{
string strBrand;
double weight;
int calories;
};

void set_candybar(TCandyBar &candbar, const char *strBrand = "Millennium Munch", double weight = 2.85, int calories = 350)
{
candbar.strBrand = strBrand;
candbar.weight = weight;
candbar.calories = calories;
}

void show_candybar(const TCandyBar &candbar)
{
cout << candbar.strBrand << 't' << candbar.weight << 't' << candbar.calories << endl;
}

int main(void)
{
TCandyBar candbar1, candbar2;
set_candybar(candbar1);
show_candybar(candbar1);
set_candybar(candbar2, "yang yang", 3.11, 256);
show_candybar(candbar2);

cout << endl;
return (0);
}
  1. 编写一个函数,它接受一个指向string对象的引用作为参数,并将该string对象的内容转换为大写,可使用函数toupper( )。然后编写一个程序,它通过使用一个循环让您能够用不同的输入来测试这个函数.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

#include <cctype>

using namespace std;

string &
str_to_upper(string &str)
{
for (auto &e : str)
{
e = (char)toupper(e);
}

return (str);
}

int main(void)
{
while (true)
{
cout << "Enter a string (q to quit): ";

string strInput;
getline(cin, strInput);
if (!cin || "q" == strInput || "Q" == strInput)
{
break;
}

cout << str_to_upper(strInput) << endl;
}

cout << endl;
return (0);
}
  1. 请提供已知代码描述的函数和原型,从而完成该程序。注意,应有两个show( )函数,每个都使用默认参数。请尽可能使用cosnt参数。set( )使用new分配足够的空间来存储指定的字符串。这里使用的技术与设计和实现类时使用的相似
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <iostream>
#include <cstring>

using namespace std;

struct stringy
{
char *str;
int ct;
};

void set(stringy &stry, const char *szTxt)
{
stry.ct = (int)strlen(szTxt);
stry.str = new char[stry.ct + 1];
strcpy(stry.str, szTxt);
}

void show(const char *szTxt, unsigned times = 1)
{
for (unsigned i = 0; i < times; ++i)
{
cout << szTxt << endl;
}
}

void show(const stringy &stry, unsigned times = 1)
{
for (unsigned i = 0; i < times; ++i)
{
cout << stry.str << endl;
}
}

void destroy(stringy &stry)
{
delete[] stry.str;
stry.str = NULL;
}

int main()
{
stringy beany;
char testing[] = "Reality isn't what it used to be.";
set(beany, testing);

show(beany);
show(beany, 2);
destroy(beany);

testing[0] = 'D';
testing[1] = 'u';
show(testing);
show(testing, 3);
show("Done!");

return 0;
// prints member string once
// prints member string twice
// prints testing string once
// prints testing string thrice
}
  1. 编写模板函数max5( ),它将一个包含5个T类型元素的数组作为参数,并返回数组中最大的元素(由于长度固定,因此可以在循环中使用硬编码,而不必通过参数来传递)。在一个程序中使用该函数,将T替换为一个包含5个int值的数组和一个包含5个dowble值的数组,以测试该函数.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <iostream>
#include <array>

using namespace std;

template <typename T>
const T &
max5(const array<T, 5> &arr)
{
unsigned idxMax = 0;
for (unsigned i = 0; i < 5; ++i)
{
if (arr[i] > arr[idxMax])
{
idxMax = i;
}
}

return (arr[idxMax]);
}

int main(void)
{
array<int, 5> iArray = {{32, -1, 99, 256, 9}};
for (const auto &e : iArray)
{
cout << e << ' ';
}
cout << " ----max: " << max5(iArray) << endl;

array<double, 5> dArray = {{-3.2, 221.22, 9.9, 0, 1}};
for (const auto &e : dArray)
{
cout << e << ' ';
}
cout << " ----max: " << max5(dArray);

cout << endl;
return 0;
}
  1. 编写模板函数maxn( ),它将由一个T类型元素组成的数组和一个表示数组元素数目的整数作为参数,并返回数组中最大的元素。在程序对它进行测试,该程序使用一个包含6个int元素的数组和一个包含4个double元素的数组来调用该函数。程序还包含一个具体化,它将char指针数组和数组中的指针数量作为参数,并返回最长的字符串的地址。如果有多个这样的字符串,则返回其中第一个字符串的地址。使用由5个字符串指针组成的数组来测试该具体化。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <iostream>
#include <cstring>

using namespace std;

template <typename T>
const T &
maxn(const T arr[], unsigned n)
{
unsigned idxMax = 0;
for (unsigned i = 0; i < n; ++i)
{
if (arr[i] > arr[idxMax])
{
idxMax = i;
}
}

return (arr[idxMax]);
}

const char *
maxn(const char *arr[], unsigned n)
{
unsigned idxMax = 0;
for (unsigned i = 0; i < n; ++i)
{
if (strlen(arr[i]) > strlen(arr[idxMax]))
{
idxMax = i;
}
}

return (arr[idxMax]);
}

int main(void)
{
int iArray[] = {32, -1, 99, 0, 256, 9};
for (const auto &e : iArray)
{
cout << e << ' ';
}
cout << " ----max: " << maxn(iArray, sizeof(iArray) / sizeof(iArray[0])) << endl;

double dArray[] = {-3.2, 221.22, 9.9, 0, 1};
for (const auto &e : dArray)
{
cout << e << ' ';
}
cout << " ----max: " << maxn(dArray, sizeof(dArray) / sizeof(dArray[0])) << endl;

const char *szArray[] = {
"aa aa",
"dddddddddddd",
"",
"fffffff ffff",
"kk kk",
};
for (const auto &e : szArray)
{
cout << '"' << e << '"' << ' ';
}
cout << " ----max: " << '"' << maxn(szArray, sizeof(szArray) / sizeof(szArray[0])) << '"' << endl;

cout << endl;
return 0;
}
  1. 使用两个名为 SumArray()的模板函数来返回数组元素的总和,而不是显示数组的内容。程序应显示thing的总和以及所有debt的总和
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <iostream>

struct debts
{
char name[50];
double amount;
};

template <typename T>
double SumArray(T arr[], int n)
{
using namespace std;
cout << "template An";
double sum = 0;
for (int i = 0; i < n; i++)
sum += arr[i];

return (sum);
}

template <typename T>
double SumArray(T *arr[], int n)
{
using namespace std;
cout << "template Bn";
double sum = 0;
for (int i = 0; i < n; i++)
sum += *arr[i];

return (sum);
}

int main()
{
using namespace std;
int things[6] = {13, 31, 103, 301, 310, 130};
struct debts mr_E[3] = {{"Ima Wolfe", 2400.0},
{"Ura Foxe", 1300.0},
{"Iby Stout", 1800.0}};
double *pd[3];
for (int i = 0; i < 3; i++)
pd[i] = &mr_E[i].amount;
cout << "the total number of Mr. E's things:n"
<< SumArray(things, 6) << endl;
cout << "the sum of Mr. E's all debts:n"
<< SumArray(pd, 3);

return 0;
}