inline函数返回值_第三章 函数

72e484b11d57615db2b110af1bb09847.png

C++学习进度好慢,是不是我的打开方式不对,所以导师给我上数据了...

上周进行了研究生生涯的第一次组会,虽然很紧张也不知道讲什么,但是开始开会的那一下子,瞬间就不紧张了,听师兄师姐讲研究进展,嗯,太厉害了,对这个方向的爱好好像就那么被再次提升了,自己汇报学习进展,好像没什么东西,最后也提了几个问题,不过最不懂的应该是那堆雷达公式和地球物理函数模型,怎么出来的,后人在研究的时候都是对这些公式进行了改进,具体算法上的改进我是看不懂了,也就明白多考虑了一定的因素,好像通了一点吧。

碎碎念:

最后确定了一个大体方向和最近的工作,实际上自己编程现在自学进度真的很慢两个星期编出一个可以读取HDF5数据,然后把测量数据和参考标准数据匹配起来生成csv的代码,嗯,听起来挺简单,excel好像就可以做到(耐心多一些),但是四天了,我现在头绪一团乱,我尝试了不学完C++直接找别人代码学,但是吧,首先我把代码粘贴过来运行都失败了,看就更。。。我现在不知道该自学还是继续看别人的代码,我有些懵,时间紧迫,我继续扣别人的代码吧还是

笔记正文

  • 导学,本章内容
    • 函数——程序的功能模块
    • 函数的定义与调用
    • 内联函数
    • constexpr函数
    • 带默认参数值的函数
    • 函数重载
    • 系统函数
  • 函数定义
    • 语法形式

dbe6eb75e17cb2444c2293ec96196637.png
    • 形参表不占空间,后面调用的时候才占用空间;相当于局部变量

1592cc0953e2de223a60e188055e7209.png

语句序列最后一句是return语句,返回类型为类型标识符的类型,如果无类型,则viod,无类型的可以不写return

  • 函数调用
    • 调用前需要先声明
      • 定义和调用可能不在一个程序中或者一个程序中定义在调用后
    • 调用形式

cce3d99ce1b9169c823268824ade1293.png
    • 递归调用
    • power为函数名,()中有参数,x和n为形参

19724cf8a030dfe450393db636454d0c.png

91a8c7e5d9f0f34a1e71829f48411812.png
  • 数制转换
    • 把二进制数转换为十进制数
    • 可以利用上面求x的n次方

04ed374789cbc7cda85294522b5e4945.png
    • 第三行声明函数原型
  • 编写程序求π

ff7345fc690d16335c9bb1d25433ad40.png
    • 用功能分解的方式,不同的函数实现不同的部分
    • 设计一个函数计算arctan:double arctan(double x)
    • 主调函数用arctan
    • 精度条件:“直到级数...”
    • 代码

b410cd7fb2e5765e3b0d06f9844cf46c.png

3726f917905b15acb99e3b233baabb41.png


整数相除1/5,结果取整,所以写的时候写1/5.0;
​ e/i>1e-15 因为限制条件是直到级数某项绝对值不大于10的-15次方为止,所以可以循环的条件就是大于10的-15次方,停止条件是小于等于10的-15次方;

  • 例题3.4

d39d9601c3bdd79555ed3eebf712d364.png
    • 判断回文数,就要使数倒过来,那么就想到了除以10取余,每次取数的最后一位

a3629c0b2f9bb043b4a26c65cbbcb8ec.png

616b7e9348d370ac50d52f73de382579.png


先翻转,除以10取余,最先取出来的数,在结果中为最高位
​m第一次的时候为0+一个数,所以第一个取出来的数是最后一位,每一次取出一个当前最低位,留商数下一次用

  • 例3-5

acdd3ae14a005b70b81ddfe412b36adb.png

d5fb73bb2d9b3983b9c9096defb7d74c.png
    • 先看k,两种关于r的条件,使用if语句
    • 多次用到了sin函数,我们在例题中自己写(库中其实有sin)
    • 精度,如果不大于了则停止
    • sin函数

657f6013094098f92fc5a7c1296d3bc3.png
    • 主函数

3aadfc413474e306d5ae01ebd6aceabb.png
  • 函数调用例3-6
    • 投骰子

b34757565f3be4329d94326a80a6c556.png


由一个函数专门模拟投骰子,另一个专门玩游戏

  • 随机数
      • rand函数
        • 函数原型:int rand(void)
        • 所需头文件:<cstdlib>
        • ​功能和返回值:求出并返回一个伪随机数
        • 每次调用它都会产生一个整数,看不出什么规律
        • 但是你下一次再从头调用的时候和上一次产生的整数一致
      • srand函数

61452be5b1dd11388bca24eba38ce59b.png
        • 为了使rand产生一个随机数序列而设置的起始点
        • 每次运行前给一个不同的种子,将产生不同的随机数列
        • 代码

e3d5068ba8e32d8b05a5f813b618ffe2.png

d2601d0c58e23cbc6b8bffae505a947b.png

911ec678926313290d2a7c138a76ca34.png
        • case 7,11共用语句
        • 投骰子过程

8f791a62e254a391b2cc2017eadcdaac.png

b1926fd52463aca9d00ec8e1d2dad431.png
  • 函数的嵌套调用
    • 用栈保存了当前现场和地址,所以能返回前一次暂停的调用点

3bf4c8032e9a07fef08f61d4cbf050b0.png
    • 例子

d5fb73bb2d9b3983b9c9096defb7d74c.png
    • 函数一调用两次函数二,函数一仅仅是加了和
    • 将求平方和这个过程分解成了求平方和求和
  • 函数的递归调用
    • 函数自己调用自己,函数直接或间接的调用自身
    • 例子

a1aef99f05758aa872ad439b607cff61.png

abb1c1107e8074b6a3d54b020bce9a98.png
      • 当你解释什么是阶乘时,你解释n的阶乘是n-1的阶乘,照此递归下去,越来越小,直到你能计算下去

cb43a917bc140992f238e63da82aec64.png
    • 递归终结条件为n==0

321fcec6b9672b1f2bd8c7d6112a24bb.png
  • 递归例题3-9
    • 题目,解释什么是组合的时候,又递归。

7221eda74e6bc27381c511dd44ddbc4c.png
    • 代码,两个递归深入,再逐级回退

4cee73327af2cb3dd3e4a1007e85b874.png
  • 例3-10汉诺塔

16d67fb0cb3b0d7c40ecf2cdc7426c70.png
    • 解析,n-1个解决不了,可以解决n-2个,等等往下推,直到某个时刻有解了,就解决了

df64f7db34ba3e2df3b4b09b228d447d.png
    • 核心

df1cfbcfdc56b37d33e5519548a4e611.png
  • 如果是一个盘子就直接移动

8e812bf7c32804cd10c3ffcfb301d66c.png
  • 函数的参数调用
    • 形参不占用内存空间,只有调用函数的时候,才会给形参空间,这叫参数传递
    • 单向传递,双向传递
    • 在函数被调用时才分配形参的存储单元
    • 实参可以是常量、变量或表达式
    • 实参类型必须与形参相符——不一样,会隐含转换,不能转会报错
    • 值传递是传递参数值,即单向传递
    • 引用传递可以实现双向传递(有的参数可以将函数的计算结果带回主调函数)
    • 常引用作参数可以保障实参数据的安全
  • 引用类型(有困惑,不完全懂)
    • 引用(&)是标识符的别名
    • 定义一个引用时,必须同时对它进行初始化,使它指向一个已存在的对象
    • 例如:
      • int i,j;
        int&ri=i;//定义int引用ri,并初始化为变量i的引用——这个变量有两个名字:i&ri
      • j=10
        ri=j;//j的值赋给ri,就相当于i=j
    • 一旦一个引用被初始化后,就不能改为指向其他对象
    • 引用可以作为形参,实现参数的双向传递
    • 不存在空引用,引用必须连接到一块合法的内存
    • 一旦引用被初始化为一个对象,就不能被指向到另一个对象。(指针可以在任何时候指向到另一个对象)
    • 引用必须在创建时被初始化。(指针可以在任何时间被初始化)
    • 引用作参数,也符合定义分配空间的时候直接初始化的原则
      • 因为函数被调用的时候才给形参分配存储空间
      • 只有行实结合的时候这个引用才被定义
      • 这个时候用实参的这个变量去初始化形参的引用
    • 交换是一个常见的操作
    • 例3-11输入两个整数并交换(值传递)——单向传递

4a22d49999b3d2a54ae5c93ca60591af.png
    • swap调用函数,void表示函数无返回,若放在函数的括号里则表示函数五参数
    • 主函数中输出的时候发现两个值并没有交换,这是为什么?前面swap函数交换两个变量的值并没有错
    • 用实参5去初始化形参a,实参10去初始化形参b,这样a和b都得到了值,但是a,b与x,y的联系从此就切断了;
    • 交换a,b的时候只是单纯的在交换a和b,根本看不到x,y,因为它是主函数的变量,到子函数中已经离开它的作用域了;
    • 返回主函数中,a,b就消亡了,输出的时候就不会有变化

301716252f4fbee29e08605456b0d11d.png
    • 参数是单向传递的,只有一开始实参和形参有联系
  • 例3-12输入两个整数交换后输出(引用传递)

892b71d9cacab42bd1df06143e31189f.png
    • int a,int b表示a,b准备好了,准备作别名用。定义函数的时候并不给它分配空间,调用的时候才会,让它与实参相结合
    • x是它,a也是它,在子函数swap中我们就实际上用a,b去操纵x,y两个量

bbb496163d1ef9b272224f54c1658ab4.png
  • 含有可变参数的函数
    • 写参数不确定的函数
    • 一般在写函数时,就把形参表确定了
    • 含有可变参数的函数的语法规定(可变长度的形参表)
      • C++标准库中提供了两种主要的方法
        • 如果所有的实参类型相同,可以传递一个名为initializer_list的标准库类型
        • 如果参数的,我们可以编写可变参数的模板(第九章)
        • initializer_list
          • 是一种标准库类型,用于表示某种特定类型的值的数组,该类型定义在同名的头文件中

3f688f8412017cd39863e814b32e00f4.png
          • 使用方法

dec2aaa011bca03d61a2b873a3b9d7b6.png
          • 使用举例
          • 在编写代码输出程序产生的错误信息时,最好统一用一个函数实现该功能,使得对所有错误的处理能够整齐划一;然而错误信息的种类不同,调用错误信息输出函数时传递的参数也会各不相同
  • 内联函数
    • 声明使用关键字inline
    • 编译器编译时用函数体里的语句替换函数表达式
    • 编译时在调用处用函数体进行替换,节省了参数传递,控制转移等开销
    • 要求
      • 内联函数体内不能有循环语句和switch语句
      • 其定义必须出现在内联函数第一次被调用之前
      • 对内联函数不能进行异常接口声明
    • 应用

73295124e02b0582524905246c242b43.png
    • inline建议编译器在我调用函数的时候直接拿内联函数来替换
  • constexpr函数
    • 语法规定
      • constexpr修饰的函数,在其所有参数都是constexpr时一定返回constexpr
    • 举例
      • constexpr int get_size(){return 20;}//这个函数返回什么值,在编译阶段编译器就可以解决,即编译期间可计算的函数
      • 可以去初始化一个常量表达式
      • constexpr int foo=get size();//foo是一个常量表达式
  • 带默认参数值的函数
    • 没给实参就用形参的默认值
    • 可以预先设置默认的参数值,调用时给出实参,则采用实参值,否则用预先设置的

0ad19c656ee4213f862a3222c9bf909e.png
    • 默认参数值的说明次序
      • 有默认参数的形参必须列在形参表的最右,即默认参数值的右边不能有无默认参数值的参数;
      • 调用时实参与形参的结合次序是从左向右

210cd5010da9297d1e996c52eee1ef4c.png
    • 默认参数值与函数的调用位置
      • 如果一个函数有原型声明,且原型声明在定义之前,则默认参数值应在函数原型声明中给出
      • 如果只有函数的定义,或函数定义在前,则默认参数值可以在函数定义中给出。

34f1c92fcf2f3cf2540652d08cb85c9a.png
      • 写一个函数,求长方体体积

bc5871f2fca91ebd53d05ef6ea55fdaf.png
      • 代码

3d9a5c19ba3c818ea53c9d3388cf3d51.png
      • 头文件为#include <iomanip>
        • 其中io代表输入输出,manip是manipulator(操纵器)的缩写
        • iomanip的作用:
          • 主要是对cin,cout之类的一些操纵运算子,比如setfill,setw,setbase,setprecision等等。它是I/O流控制头文件,就像C里面的格式化输出一样。
      • setw(int n)
        • 是c++中在输出操作中使用的字段宽度设置,设置输出的域宽,n表示字段宽度。只对紧接着的输出有效,紧接着的输出结束后又变回默认的域宽。
        • 当后面紧跟着的输出字段长度小于n的时候,在该字段前面用空格补齐;当输出字段长度大于n时,全部整体输出。
      • t:水平制表(跳到下一个Tab位置)
      • r:回车,将当前位置移到本行开头
      • n:换行
  • 函数重载
    • C++允许功能相近的函数在相同的作用域内以相同函数名声明,从而形成重载。方便使用,便于记忆。
    • 注意事项
      • 重载函数的形参必须不同:形参类型不同或形参个数不同
      • 编译器不以形参名来区分
      • 不以返回值来区分(函数的类型不同,一个int,一个void,返回值不一样,void为空

fbf7149ed193d23a7a1cbec2d0af39d9.png
      • 不要将不同功能的函数声明为重载函数,以免出现调用结果的误解、混淆。

597a2b8b93e6284d319d277cb4befd29.png
    • 例子

c916c28be6e17e0e83555241199772ba.png

1346ff0f2dd84d9cafd8f8380c87bb87.png
      • 参数类型不同
  • 系统函数
    • sin,cos什么的自己调用吧
    • 库中提供了几百个函数可供使用
    • 使用数学函数时,要使用cmath
    • 例题

db8fda49461330543b11cef5d78061e4.png

d461f137a3f7b6cda63c8f8739d1c365.png
    • 函数形参与局部变量很相似,都不能像全局变量那样用固定地址加以定位,而需要存储在一种特殊的结构中,这就是栈
    • 一般意义上的栈,是一种数据结构,它是一种能够容纳很多数据的结构,但数据进入和退出这个容器的顺序,要满足一定的要求
    • 数据只能从栈的一端存入(压入栈),只能从栈的同一端输出(弹出栈),这一端叫做栈顶,另一端叫做栈底
    • 栈中数据的添加和删除操作具有“先进后出”的特性
    • 运行栈
      • 嵌套函数中越早开始的调用,返回的越晚
        函数调用中的形参和局部变量,当调用开始时生效,当函数返回后即实效
      • 故嵌套函数中,形参和局部变量生效的时间越早,实效的时间越晚
      • 所以函数的形参和局部变量可以用栈来存储——运行栈
      • 实际上是一段区域的内存空间,与存储全局变量的空间无异,只是寻址的方式不同。
      • 运行栈中的数据分为一个一个栈帧,每个栈帧对应一次函数调用,栈帧中包括这次函数调用中的形参值、一些控制信息、局部变量和一些临时数据(中间值、返回值)
      • 一个函数在执行过程中能够直接随机访问它所对应的栈帧中的数据,即处在运行栈最顶端的栈帧的数据
      • 执行中的函数的栈帧,总处在运行栈的最顶端
      • 当一个函数调用其他函数时,要为它所调用的函数设置实参,具体方式是在调用前把实参值压入栈中,运行栈中的这一部分空间是主调函数与被调函数都可以直接访问的,参数的形实结合就是通过访问这一部分公共空间完成的
      • 虽然一个函数在被调用时的形参和局部变量地址是不确定的,但是它们的地址相对于栈顶的地址却是确定的,这样就可以通过栈顶的地址,定位形参和局部变量
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值