当前课程知识点:C++语言程序设计基础 >  第3章 函数 >  实验三(上)函数的应用 >  实验三(上)函数的应用

返回《C++语言程序设计基础》慕课在线视频课程列表

实验三(上)函数的应用在线视频

实验三(上)函数的应用

下一节:实验三(下)函数的应用

返回《C++语言程序设计基础》慕课在线视频列表

实验三(上)函数的应用课程教案、知识点、字幕

大家好

欢迎来到实验3的上半部分

本章的学习目标

是掌握将一段功能独立的程序

写成一个函数

为今后学习类和对象

打下一个必要的基础

本部分的实验内容

是通过实验练习

来进一地理解和掌握

函数的定义

和调用的方法

并且掌握

debug中的step into方法

来跟踪到函数的内部

说到函数

大家首先想到的

就是数学中的函数吧

那么本章的第一个例子

就来练习一下

如何用C++中的函数模块

来实现一个数学中的简单函数

其实掌握函数的定义

和基本的语法比较简单

它的主要难点在于

如何去理解和跟踪

函数的调用过程

以及它的参数传递

在本章中

郑莉老师给大家介绍的例子

明显比第二章复杂

其中包含大量有用的算法

并附有详细的注释

建议大家仔细地阅读

并亲自上机调试

还记得我们之前给大家说过的

学习编程从修改例子程序开始吗

在调试程序的时候

将利用本章介绍的step into功能

跟踪到函数的内部

能够帮助我们理解

整个函数执行的过程

和参数的传递

郑老师还给大家介绍了递归算法

一种用途广泛

简捷高效的算法

这种算法理解起来

有一定的难度

本部分的第二个例子

就将以一个简单的递归程序为例

介绍step into

这个debug功能

跟踪递归算法的过程

首先我们来看例题一

编写一个函数

函数的名称叫Convert

它的参数和返回值都为float类型

这个Convert函数

需要实现一个算法

如图上所说的这个公式

这个算法呢

它是把一个华氏温度

转化成一个摄氏温度的一个公式

接下来我们来看一下

已经编写好的这个代码

在这里

我们函数名称叫Convert

这里有一个函数

那么Convert函数呢

大家看看它函数体非常简单

只有三行

这三行代码就实现了

用C++语言来把相应的算法

翻译成C++代码

来实现函数相应的功能

数学函数呢

是用最直接的翻译方式

大家看到

我们直接把公式列在这里

F减去32 乘以5 除以9

然后复制给C

在这里呢F是形参

它的类型是float

然后C呢是函数内部的局部变量

它的类型也是float

当C的值计算完毕之后

通过return语句

作为函数的返回值

进行函数参数的返回

那在这个例子里

我们可以看到

我们把这个函数Convert

写在main函数之前

完成了函数的定义

这一部分的工作

那么在定义完了

Convert这个函数之后呢

我们在main函数中

通过几个简单的步骤

来获得用户

对于华氏摄氏度输入

然后通过调用

我们刚才定义的这个Conver函数

来验证一下

这个函数的调用

是否如我们预想的那样

是正确进行的

那么在调试之前呢

想给大家介绍一个新的调试功能

就叫step into

也可以通过f11来启动它

那么和我们之前给大家介绍的

逐过程 step over

或者是f10对应的这个

单步调试的功能所不同呢

f10是直接会

越过整个函数的执行

直接给出函数执行的结果

而f11逐语句step into呢

它遇到常数调用的时候

会进入函数的内部

我们在这一章学习了函数

为了更好地跟踪和了解

函数调用之后

进入到函数体中

一步一步地执行过程

所以我们选择f11

step into的这种方式来跟踪

会比较清楚

我们从f11开始

我们可以看到

从这个窗口里头看到

我们这里声明了

在main函数中声明了这个

一个float类型的变量叫F

那么在main函数的第一条语句

就是光标所指的位置

这个时候呢

只是把变量名和变量类型

已经声明了

但是F并没有进行初始化

我们在调用堆栈这里也可以看到

在这里我们运行到

main函数的第19行

接着我们再用逐语句的方式

来进行运行

这个时候就进行到了

main函数的第23行

这个时候屏幕会输出

让用户输入一个华氏度的

这样一个温度值

我们来看一下

屏幕上就显示出了这样一行文字

接下来呢

我们把光标放到这里

放到调用Convert函数的这一行

27行

然后点击右键

选择运行到光标

或者按下Ctrl f10

然后让编译器调试的过程呢

直接运行到Convert这一步

然后再停下来

这个时候

我们可以输入一个

你想要的华氏的温度

比如说100度吧

那可以看到

这个时候呢

光标就停在了刚才我们设立

执行位置的地方

main函数中的27行

同时呢

刚才我们用户的键入100

也正确地通过cin

读入到了变量F中去

这个时候F的值变成了100

接下来我们

不想通过以前的f10

step over的方式

直接看到Convert函数

执行的结果

而是我们想跟踪一下

当调用Convert的时候

整个调用执行的过程

那这个时候我们就选择F11

step into

这个时候光标挪到了

Convert这个函数的第一行

也就是

现在我们跟踪到了

Convert调用的内部

那我们在调用堆栈里头

也可以看到这个时候

我们运行的位置是

Convert这个函数的

它的运行的函数是第11行

在Convert函数内部呢

我们有两个局部的量

一个F 一个是C

F的值通过刚才函数的调用

已经进行了初始化

所以F的值是100

那变量C呢

只是进行了名称和类型的声明

还并没有初始化

所以我们在这里看到的是一个

随机的一个数

那我们接下来再一步一步地进行

那么这个时候

光标指向了第14行

也就是这个数学公式计算之前

那么再往下走一步

这个时候我们看到

通过刚才的计算

局部变量C的值已经被改变了

变成了一个37.77777786

这样的一个浮点数

接着我们到了

整个Convert函数的最后一句

return C

那么它就是将把C当前所用的值

作为Convert整个函数的返回值

返回到main函数中去

返回以后呢

我们可以看到

光标又回到了刚才

main函数中的27行

就是返回到了main函数中

刚才调用Convert函数的位置

这个时候返回值

通过cout这个输出流对象

进行输出

我们再往下执行一步

就可以看到

在这里显示出了

通过调用Convert函数以后

返回到main函数中去

通过cout输出的这个摄氏的温度

通过这个例子呢

又复习一下函数的定义

和调用

了解了如何用一个C++语言函数

来翻译数学函数

并且更重要的是

我们在这里给大家介绍了

用step into

还有run to cursor这两种手段

来跟踪整个函数的调用过程

察看函数调用时

不同参数的值

以及运行到调用堆栈的位置

以及行数

这对于我们来跟踪调试

和理解函数的执行 调用

参数的传递

和参数的返回

是非常有帮助的

接下来我们来看例题二

例题二是要求大家

编写一个递归函数

就是著名的Fibonacci数列

大家可以看到

它的参数只有一个

是整型的int类型

返回值也是int类型

要求在主程序中

通过键盘来输入n的值

然后调用Fibonacci函数

来计算Fibonacci级数

这里我们来看一下

Fibonacci级数的计算公式

它是一个

非常典型的分段函数的形式

当参数值为1和2

也就是第一个

和第二个Fiboacci级数

它的值都为1

那么当n大于2开始呢

Fibonacci级数的第n个

等于它在第n-1个

和第n-2个之和

接下来我们来看一下

我们准备好的这个代码

那么在这个例子中

我们跟例一有所不同

我们把Fibonacci

这个函数的实现呢

放到了main函数调用的之后

可以看到

把它main函数之后

所以我们在这里

也需要在main函数之前

也就是调用之前

进行一个函数原型的声明

来告诉编译器

存在这样一个函数的声明

和定义

并且我们接下来马上就要使用它

那么我们言归正传

我们来看一下main函数

那么按照题目的意思

我们需要由两个int类型参数

一个是n

给出我要

求Fibonacci级数的第几个

另外一个是answer

计算出来的Fibonacci数列的

第n个级数到底应该是多少

接下来我们用cout

提示用户输入一个数

这个数是级数的第几个

并且把这个数

通过cin存入到变量n中去

我们在这里的cout

是打印两个换行符

是为了把

Fibonacci级数的计算结果

和刚才的输入进行分隔

那大家可以根据自己的喜好

进行不同的输入输出语句的

这个格式调整

目的首先是清楚

然后如果能美观那就更好了

接下来我们就

调用了Fibonacci函数

fib这个函数

那把刚才从界面上读的n

作为参数的值传入进去

它的结果赋值给answer

这样一个变量

接下来通过cout

把计算出来的第n个

Fibonacci级数的值打印输出

这就是main函数的功能

非常简单

接下来我们来看一下

Fibonacci函数的对应实现

fib这个函数

fib函数有一个形式参数

int类型的变量n

那么需要注意的是

尽管在这里有一个n

然后在main函数中有一个n

同时它们的类型都是int类型

但实际上这是

两个完全不相干的两个参数

那么它们的生存区

和作用域

也是各不相同的

在调用的这一时刻

会把主函数中的n的值

传递到fib这个函数的形参中去

那传输完毕以后呢

这两个n就完全没有关系了

对这个n的任何操作和改变

都不会影响main函数的这个n

那么在fib这个函数的内部呢

也是为了便于观测

整个函数的执行过程

我们在这里打印输出

Processing fib

也就是告诉我们的观察者

或程序人员

我们已经进入fib这个函数了

同时把这个n也输出

就是说

我接下来要计算的

是级数的第n个

这个n的值是多少

接下来要做一个判断

因为我们刚才说到

Fibonacci函数

是一个典型的分段函数

所以显然

我们应该用if else分支

来进行分情况的计算和讨论

那么n等于1和2的时候呢

Fibonacci级数的值都是1

所以在这里if n小于3

那么直接把整数1作为返回值

进行返回

并且打印输出返回1

那当n的值是大于或等于3的时候

我们就需要

进行一个级数的递归运算

我们在这里打印输出

按照Fibonacci计算的公式

当n大于等于3的时候

那么它的级数应该是把

第n-2个Fibonacci级数

和第n-1个Fibonacci级数相加

然后作为第n个级数的返回值

进行返回

那么在这里

因为我们在fib这个函数内部

又调用了fib这个函数自己

只是参数的规模进行了缩减

所以这是一个

非常非常典型的函数

自己调用自己的例子

也就是我们说的递归调用

那么接下来我们就要

仍然会应用

刚才给大家介绍的step into功能

和run to cursor功能
来观测一下

这个递归的调用过程

和参数传递的情况

我们还是用f11

好 我们调试开始了

那么首先f11呢

最后进入main函数

并且在main函数

并且在main函数的第一行停住

在main函数中

我们这里声明了两个

int类型的变量

一个是answer 一个是n

这个时候呢

它们都没有进行初始化

因为它们是一个内存中任意的值

我们在调用栈里头可以看到

这个时候光标是停在了

main函数的里面

而且行数是第13行

接下来呢

我们把光标放到

answer等于fib(n)这一行

通过右键选择运行到光标处

这个时候要我们去输入一下

这个级数n的值

在这里我们先输入一个2

来试一下

也就是没有发生递归

或者是递归的最简单情形

那这个时候n的值是2

通过cin来读入了

并且整个调试过程停到了

这个黄色箭头所指的光标处

在调用栈里我们也可以看到

现在执行到了main函数的第18行

但是n的值呢

也正常地被刷新为2

接下来我们想跟踪一下

它进入

fib这个函数之后的执行过程

这个时候你可以按一下f11

大家可以看到

现在光标停在的位置

这是正常的进入了fib这个函数

并且停在了它的第一行

在调用栈我们可以看到

这个时候我们运行到的是

在main函数之内

我们又进入了fib这个函数

并且停在了第24行

这个位置

我们再来看一下局部变量

在fib这个函数中

只有一个局部变量

它是n

这个时候显示n的值是2

也就是在这次调用中

main函数中的n值

已经正常地传递到了fib函数中

使它的n值也为2

那接下来呢

因为n值为2

所以它肯定会选择if分支中的

哪一个分支呢

对 显然是第一个分支

就是小于3的情况

这个时候不做进一步的递归

而是直接返回整数1

我们来单步跟踪一下

果然

因为n的值是2

2小于3

使得if后面的这个条件判断成立

就进入了if分支

这个时候我们来看一下

都输出了什么

这个时候输出的是

我们正在处理的是

Fibonacci函数中的第二个级数

我们再来看一下

这个时候打印出来返回1

说明进入了if的这个第一个分支

那现在光标就跳到了

整个fib函数的最后

末尾部分的这个第36行

也就是它的结束之处

意味着这个函数的执行完成了

并没有去执行else分支

后面的这半部分

那我们再看一下

它如何返回的

这个时候光标又退回到了

main函数中的第18行

就是在这里

可以看到这个时候呢

answer的值还没有被赋值

而fib函数结束了

返回的值呢是1

我们再来进行一步

这个时候可以看到

返回值

那个临时的无名变量的1的值

复制给了answer这个变量

使得answer的值为1

完成了我们的计算

也就是n等于2的时候

Fibonacci级数的值是1

那最后就是打印输出我们的结果

您可以看到

输出Fibonacci数列的

第二个级数的值是1

那么这个最简单情形的调试

我们就结束了

接下来我们希望观测什么呢

观测n大于等于3的时候

Fibonacci数列这个fib函数

会自己调用自己

这个时候才进行了

一个真正的递归的调用的过程

我们再来跟踪一次

首先还是通过f11

进入到main函数的第一行

接着我们还是把光标

设在answer等于fib(n)这里

运行到光标处

那这次呢

我们输入4来试一试

因为4是大于等于3的

所以它必然会进行一个

真正的递归调用

可以看到这个时候呢

光标停在这个地方

然后n的值呢通过键盘读入

变成为4

接着我们通过f11

来运行到fib函数的内部

它停在了fib函数的第1行

也就是对应的24行这里

这个时候的n值变成了4

局部变量n值变成了4

显然它是要执行else分支的

我们再次把光标放到return

递归调用的这个地方

运行到光标处

这个时候我们可以看到

它确实进行了

进入到了else分支里

并且正常地打印出了

这个时候它要调用

Fibonacci级数的第二个级数

和Fibonacci级数的第三个级数

这个时候自己调用了自己一次

这时候是进行了

递归调用的第一层

但是事情还没有结束

因为即使是

Fibonacci的第二个级数

和第三个级数

它也是需要进一步进行递归的

那我们可以看到

因为我们刚才用了f10

step over就完成了

整个递归调用的过程

接下来的分解

应该是先去调用

从Fibonacci第二个级数进行深入

然后返回呢 值是1

然后再从

Fibonacci数列第三个级数

开始深入

它进入了

Fibonacci的第三个级数之后呢

再去进一步地分解调用

Fibonacci的第一个级数

和第二个级数

那遇到Fibonacci的

第一个级数的时候

返回 为1

遇到第二个级数的时候

返回 也为1

这样共同返回就到了

Fibonacci的第三个级数这里

那么整个递归调用的过程

结束以后呢

它又会回到main函数的这一行

那这个时候呢

我们的这个fib函数呢

返回值是3

这时候有一个临时无名的变量

我们还没有完成复制这一步

那我们再来完成这一步

这个时候把返回值3

赋值给了answer这个变量

所以最后的结果应该是输出

Fibonacci的第四个级数的值

应该是3

我们就会看到这个结果

那么我们选这个n为4的情况呢

实际上是真正的递归调用中

最简单的一种情形

那么 对 还有3

3和4是最简单的两种情形

因为时间的关系呢

在这里不可能把n的值

设得特别大

然后一层一层地来跟踪

所以接下来的扩展类型呢

是大家可以尝试把n的值

设得大一点

比如说8 9 或者是10

并且跟踪的时候呢

用一张大白纸来记录下

每一层递归的调用的过程

以及每次传递的参数

那么这样一次深度地

跟踪下来之后呢

大家一定会对递归的理解

和利用会更加地熟悉

并且对于step into

和run to cursor

这样两个debug功能的用法

也会更加地熟悉

掌握函数的定义和调用

其语法并不难

难的是理解其执行过程

和参数传递

debug中的step into功能

可以简单有效地帮助我们

本章中的递归函数

理解起来有难度

自己亲自编写

更不是一件容易的事情

作为初学者不要着急

本章中只是介绍了C++中

支持递归函数的调用

如果想深入地理解

和熟练地编写

建议大家去扩展阅读一下

数据结构中的相应章节

最后在调试递归函数的时候

建议大家准备一张大纸

记录下step into跟踪时

每一次函数调用

和参数传递的值

这样也是一个简单有效的方法

实验3的上半部分就到这里

我们下次再见

C++语言程序设计基础课程列表:

第1章 绪论

-导学

--第1章导学

-计算机系统简介

--计算机系统简介

--计算机系统简介 测试题

-计算机语言和程序设计方法的发展

--计算机语言和程序设计方法的发展

--计算机语言和程序设计方法的发展 测试题

-面向对象的基本概念

--面向对象的基本概念

--面向对象的基本概念 测试题

-程序的开发过程

--程序的开发过程

--程序的开发过程 测试题

-信息的表示和储存

--计算机中的信息与存储单位

--计算机的数字系统

--数据的编码表示

--信息的表示和储存 测试题

-实验指导

--实验一:VS开发环境介绍

第2章 C++简单程序设计(一)

-导学

--第二章导学

-C++语言概述

--C++的特点和程序实例

--C++字符集和词法记号

--C++语言概述 测试题

-基本数据类型、常量、变量

--基本数据类型、常量、变量

--程序举例

--基本数据类型、常量、变量 测试题

-运算与表达式

--算术运算与赋值运算

--逗号运算、关系运算、逻辑运算和条件运算

--Sizeof运算、位运算

--运算优先级、类型转换

--运算与表达式 测试题

-实验二:简单程序设计(上)

--实验二:简单程序设计(上)

第2章 C++简单程序设计(二)

-数据的输入和输出

--数据的输入和输出

--数据的输入和输出 测试题

-选择结构

--if语句

--switch语句

--选择结构 测试题

-循环结构

--循环结构——while语句

--do-while语句

--for语句

--嵌套的控制结构、其他控制语句

--循环结构 测试题

-自定义类型

--自定义类型

--自定义类型

-第2章小结

--第二章小结

-实验二:C++简单程序设计(下)

--实验二C++简单程序设计(下)

第3章 函数

-导学

--导学

-函数定义

--函数定义

--函数定义 测试题

-函数调用

--函数调用(例3-1)

--例3-2

--例3-3

--例3-4

--例3-5

--例3-6

--函数调用 测试题

-嵌套与递归

--函数的嵌套调用(例3-7)

--函数的递归调用(例3-8)

--例3-9

--例3-10

--嵌套与递归 测试题

-函数的参数传递

--函数的参数传递

--函数的参数传递 测试题

-引用类型

--引用类型(例3-11)

--引用类型 测试题

-含有可变参数的函数

--含有可变参数的函数

--含有可变参数的函数 测试题

-内联函数

--内联函数(例3-14)

--内联函数 测试题

-constexpr函数

--constexpr函数

--CONSTEXPR函数课后习题

-带默认参数值的函数

--带默认参数值的函数

--默认参数值例(3-15)

--带默认参数值的函数 测试题

-函数重载

--函数重载(例3-16)

--函数重载 测试题

-C++系统函数

--C++系统函数(例3-17)

--C++系统函数习题

-第3章小结

--第三章小结

-实验三(上)函数的应用

--实验三(上)函数的应用

-实验三(下)函数的应用

--实验三(下)函数的应用

第4章 类与对象

-导学

--导学

-面向对象程序的基本特点

--面向对象程序的基本特点

--面向对象程序的基本特点 测试题

-类和对象

--类和对象的定义

--类和对象的程序举例

--类和对象 测试题

-构造函数

--构造函数基本概念

--构造函数例题(1)——例4-1

--构造函数例题(2)——例4-2

--委托构造函数

--复制构造函数

--复制构造函数调用举例

--构造函数 测试题

-析构函数

--析构函数

--析构函数 测试题

-类的组合

--类的组合

--类的组合程序举例

--前向引用声明

--类的组合 测试题

-UML简介

--UML简介

--UML简介课后习题

-结构体与联合体

--结构体(例4-7)

--联合体(例4-8)

--结构体与联合体 测试题

-枚举类

--枚举类

--枚举类 测试题

-第4章小结

--第四章小结

-实验四(上)

--实验四(上)

-实验四(下)

--实验四(下)

第5章 数据的共享与保护

-导学

--导学

-标识符的作用域与可见性

--标识符的作用域与可见性

--标识符的作用域与可见性 测试题

-对象的生存期

--对象的生存期

--对象的生存期 测试题

-类的静态成员

--静态数据成员(例5-4)

--静态函数成员(例5-5)

--类的静态成员 测试题

-类的友元

--类的友元(例5-6)

--类的友元 测试题

-共享数据的保护

--共享数据的保护(例5-7)

--共享数据的保护 测试题

-多文件结构和预编译命令

--多文件结构和预编译命令(例5-10)

--多文件结构和预编译命令 测试题

-第5章小结

--小结

-实验五

--实验五

第6章 数组、指针与字符串(一)

-导学

--导学

-数组的定义与初始化

--数组的定义与使用

--数组的储存与初始化

--一维数组应用举例

--数组的定义与初始化 测试题

-数组作为函数的参数

--数组作为函数参数(例6-2)

--数组作为函数的参数 测试题

-对象数组

--对象数组

--对象数组 测试题

-基于范围的for循环

--基于范围的for循环

-指针的定义和运算

--指针的概念、定义和指针运算

--指针的初始化和赋值

--指针的算术运算、关系运算

--指针的定义和运算 测试题

-综合实例

--综合实例

-实验六(上)

--实验六上

第6章 数组、指针与字符串(二)

-指针与数组

--用指针访问数组元素

--指针数组

--指针与数组 测试题

-指针与函数

--以指针作为函数参数

--指针类型的函数

--指向函数的指针

--指针与函数 测试题

-对象指针

--对象指针

--对象指针 测试题

-动态内存分配

--动态分配与释放内存

--申请和释放动态数组(一)

--申请和释放动态数组(二)

--动态内存分配 测试题

-智能指针

--智能指针

-vector对象

--vector对象

--vector对象 测试题

-对象复制与移动

--深层复制与浅层复制

--移动构造

--对象复制与移动 测试题

-字符串

--C风格字符串

--string类

--字符串 测试题

-第6章小结

--第六章小结

-综合实例

--综合实例

-实验六(下)

--实验六(下)

实验三(上)函数的应用笔记与讨论

也许你还感兴趣的课程:

© 柠檬大学-慕课导航 课程版权归原始院校所有,
本网站仅通过互联网进行慕课课程索引,不提供在线课程学习和视频,请同学们点击报名到课程提供网站进行学习。