C++

C++plus6th 第7章函数(上)

2021-03-21  本文已影响0人  Leon_Geo

第七章 函数(模块)

1. 关于函数返回值

注意:在C++中,括号为空与在括号中使用void关键字是等效的。但在ANSI C中,括号为空意味着不明确指出参数。在C++中,表示不明确指出参数列表使用省略号(3个连续点号)。通常,仅当与接受可变参数的C函数(如printf())交互时才需要这么做。

2.关于数组作为函数参数

C++通常按值传递参数,即将实参(argument)赋值给形参(parameter)后进行运算。这样不会因为函数调用而影响到实参的值。

image-20210317233456734

假设编写一个处理double数组的函数。

如果该函数要修改数组,其原型如下:

void func_modify(double arr[], int size);

如果该函数不修改数组,其原型如下:

void func_no_change(const double arr[], int size);

当然,在原型中可以省略形参名,也可以将返回类型指定为其它类型。此处的要点是arr实际上是一个指向数组首元素的指针。注意:在函数内部不能通过sizeof(arr) 获取数组长度,而必须通过参数size传入。

指针加减法都是以指针所指向数据类型为单位进行的,例如:&arr[19] - &arr[0] = 19, &arr[0] + 1 = &arr[1]。

<pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="c++" cid="n40" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px 0px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> int age = 18;
const float length = 180;
const int * p = &age; // 一级指针下合法。
float * pl = &length; // 不合法!

*p = 20; //错误,利用p表达式指向的地址单元存贮的元素不能变。

age = 20; //成功,因为age声明本身就是一个非常量变量,它可以改变,只是不能利用p进行改变而已。</pre>

image-20210319222350563

假设存在如下二维数组int arr[3][2] = {{1,2},{3,4},{5,6}};,当其作为参数需要被传入函数sum()时,可以采用如下两种原型:

int sum(int (*arr)[2], int row);或者int sum(int arr[][2], int row);

arr[3]里存的3个元素是含有2个int元素的数组地址,因为*arrarr[]是可以相互转换的,所以存在以上两种写法,但显然后一种更容易理解。

因为arr指针类型决定了sum函数只能接受2列二维数组,但row变量指定了行数。

3.关于结构体作为函数参数

结构体作为函数参数或返回值时是作为一个整体进行值传递的,且结构体变量名并不代表结构体地址,而必须前缀&符号。但如果结构体很大,则也可以采用结构体地址作为参数,另外C++中还提供了引用传递来解决这个问题。

4.关于string对象作为函数参数

虽然字符串和string类对象的用途几乎相同,但与数组相比,string对象与结构体更相似。它们都可以作为一个整体传递给函数,也可以相互间直接赋值。如果需要多个字符串,可以声明多个string对象,而无需建立二维数组。

下面的程序声明了一个string对象数组,并将该数组传递给一个函数以显示字符内容:

<pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="c++" cid="n57" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px 0px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> //XXX.cpp -- handing an array of string objects

include <iostream>

include <string>

using namespace std;
const int SIZE = 5;
void display(const string sa[], int n);

int main()
{
string list[SIZE];
cout << "Enter your " << SIZE << "favorite astronomical sights:\n";
for (int i = 0; i < SIZE; i++)
{
cout << i+1 << ": ";
getline(cin, list[i])
}

cout << "Your list:\n";
display(list, SIZE);

return 0;
}

void display(const string sa[], int n)
{
for (int i = 0; i<n; i++)
cout << i+1 <<": " << sa[i] << endl;
}</pre>

5.关于array对象作为函数参数

因为类对象是基于结构的,因此类对象和结构体一样可按值将对象传递给函数,此时函数处理的是类对象的副本;也可传递对象的地址,这样可以处理原始对象。要使用array类,需要包含头文件array,且命名快进为std。

如果要使用array对象(名为arr_name)存储4个double型元素,可以按此定义:std::array<double, 4> arr_name;

6. 关于递归

通常将递归调用放在if语句中,其结构如下:

<pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="c++" cid="n68" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px 0px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> void recurs(参数列表)
{
语句1
if (测试语句)
recurs(参数列表)
语句2
}</pre>

测试语句终会为false,调用解开。

只要测试语句为真,每个recurs()调用都将执行语句1,然后再调用下一层recurs(),而不会执行语句2,直到测试语句为假,当前调用解开循环链,返回后将控制权交予上一层调用,而上一层执行语句2后再网上一层释放控制权,依次类推。如果recurs()进行了5次递归调用,则语句1将按照函数调用顺序执行5次,然后语句2将以相反的顺序执行5次。

请看示例:

<pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="c++" cid="n72" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px 0px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> #include <iostream>
void countdown(int n);

int main()
{
countdown(4);
return 0;
}

void countdown(int n)
{
using namespace std;
count << "Counting down ... " << n << endl;
if (n>0)
countdown(n-1);
count << n << ": Kaboom!\n";
}


下面是程序输出:
Counting down ... 4 //第1层
Counting down ... 3 //第2层
Counting down ... 2 //第3层
Counting down ... 1 //第4层
Counting down ... 0 //第5层
0: Kaboom! //第5层,开始返回
1: Kaboom! //第4层,开始返回
2: Kaboom!
3: Kaboom!
4: Kaboom! //第1层,开始返回</pre>

注意:每一层调用,函数都将创建自己的变量存储区,所以如果嵌套过深,对系统内存消耗很大。

<pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="c++" cid="n77" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px 0px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> void subdivide(char ar[], int low, int high, int level)
{
if (level == 0) //递归终止条件
return;
int mid = (high + low) / 2;
ar[mid] = '|';
subdivide(ar, low, mid, level-1);
subdivide(ar, mid, high, level-1);
}</pre>

7. 关于函数指针

<pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="c++" cid="n115" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px 0px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> double * func(const char[], int n)
{
...
}

auto pf = func; //auto将自动推断出pf的类型应该为指向func()一类函数的指针;</pre>

<pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="c++" cid="n120" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px 0px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> typedef const double (p_fun)(const double *, int); //p_fun作为某型函数指针类型
p_fun p1 = fun_1; //利用p_fun来定义变量p1</pre>

上一篇下一篇

猜你喜欢

热点阅读