函数简介

  • 函数的基本知识
  • 函数参数和按值传递
  • 函数和数组
  • 函数和C-风格字符串
  • 函数和结构
  • 递归
  • 函数指针
  • 总结

函数的基本知识

  • 创建函数时,必须完成如下工作:提供函数定义;提供函数原型;调用函数。
  • C++对于函数返回值的类型有一定的限制:不能是数组,但可以是其他任何类型——整数、浮点数、指针,甚至可以是结构和对象。
  • 函数原型不要求提供变量名,有类型列表就足够了。通常,在原型的参数列表中,可以包括变量名,也可以不包括。原型中的变量名相当于占位符,因此不必与函数定义中的变量名相同。
  • 函数原型的功能:
    1. 编译器正确处理函数返回值;
    2. 编译器检查使用的参数数目是否正确;
    3. 编译器检查使用的参数类型是否正确,如果不正确,则转换为正确的类型(如果可能的话)。在编译阶段进行的原型化被称为静态类型检查(static type checking)。

函数参数和按值传递

  • 用于接收传递值的变量被称为形参;传递给函数的值被称为实参。
  • 如果函数的两个参数的类型相同,则必须分别指定每个参数的类型,而不能像声明常规变量那样,将声明组合在一起;原型中的变量名不必与定义中的变量名相同,而且可以省略;提供变量名将使原型更容易理解,尤其是两个参数的类型相同时。
  • 对于(10 * 9) / (2 * 1)(10 / 2) * (9 / 1),前者将计算90 / 2,得到45;后者将计算为5 * 9,得到45。当数字非常大时,这种交替进行乘除运算的策略可以防止中间结果超出最大的浮点数。

函数和数组

  • 在C++中,当(且仅当)用于函数头或函数原型中,int *arrint arr[]的含义才是相同的。它们都意味着arr是一个int指针。将指针(包括数组名)加1,实际上是加上了一个与指针指向的类型的长度(以字节为单位)相等的值。对于遍历数组而言,使用指针加法和数组下标时是等效的。

  • 传递常规变量时,函数将使用该变量的拷贝;但传递数组时,函数将使用原来的数组。实际上,这种区别并不违反C++按值传递的方法,函数仍传递一个值,这个值被赋给一个新变量,但这个值是一个地址,而不是数组的内容。

  • 将数组地址作为参数可以节省复制整个数组所需的时间和内存。

  • 对于处理数组的C++函数,必须将数组中的数据种类、数组的起始位置和数组中元素数量提交给它;传统的C/C++方法是,将指向数组起始处的指针作为一个参数,将数组长度作为第二个参数(指针指出数组的位置和数据类型);还有另一种给函数提供所需信息的方法,即指定元素区间(range),这可以通过传递两个指针来完成:一个指针标识数组的开头,另一个指针标识数组的尾部。

  • 写个例子加深一下各方面理解:

    #include <iostream>
    const int Max = 5;
    int fill_array(double ar[], int limit);
    void show_array(const double ar[], int n);  // do not change data
    void revalue(double r, double ar[], int n);int main()
    {using namespace std;double properties[Max];int size = fill_array(properties, Max);show_array(properties, size);if (size > 0){cout << "Enter revaluation factor: ";double factor;while (!(cin >> factor))   // bad input{cin.clear();while (cin.get() != '\n')continue;cout << "Bad input; Please enter a number: ";}revalue(factor, properties, size);show_array(properties, size);}cout << "Done.\n";cin.get();cin.get();return 0;
    }int fill_array(double ar[], int limit)
    {using namespace std;double temp;int i;for (i = 0; i < limit; i++){cout << "Enter value #" << (i + 1) << ": ";cin >> temp;if (!cin)   // bad input{cin.clear();while (cin.get() != '\n')continue;cout << "Bad input; input process terminated.\n";break;}else if (temp < 0)  // signal to terminatebreak;/// 如果输入错误或者负值,则终止输入,返回当前输入值的数量;否则将输入值增加到数组中ar[i] = temp;}return i;
    }void show_array(const double ar[], int n)
    {using namespace std;for (int i = 0; i < n; i++){cout << "Property #" << (i + 1) << ": $";cout << ar[i] << endl;}
    }void revalue(double r, double ar[], int n)
    {for (int i = 0; i < n; i++)ar[i] *= r;
    }
  • 指针和const

    1. 可以用两种不同的方式将const关键字用于指针。第一种方法是让指针指向一个常量对象,这样可以防止使用该指针来修改所指向的值,第二种方法是将指针本身声明为常量,这样可以防止改变指针指向的位置。

    2. 举个例子来说明一下:

      int age = 39;
      const int * pt = &age;
      

      pt的声明并不意味着它指向的值实际上就是一个常量,而只是意味着对pt而言,这个值是常量。例如,pt指向age,而age不是const。可以直接通过age变量来修改age的值,但不能使用pt指针来修改它。同时,该声明中的const只能防止修改pt的值(这里是39),而不能防止修改pt的值。也就是说,可以将一个新的地址赋给pt

      再比如:

      int sloth = 3;
      const int * ps = &sloth;         // a pointer to const int
      int * const finger = &sloth;    // a const pointer to int
      

      在最后一个声明中,关键字const的位置与以前不同,这种声明格式使得finger只能指向sloth,但允许使用finger来修改sloth的值。也就是,地址是常量。

      如果愿意的话,还可以声明指向const对象的const指针:

      double trouble = 2.98;
      const double * const stick = &trouble;
      
    3. 综上来讲,其实有四种组合关系:将常规变量的地址赋给常规指针;将常规变量的地址赋给指向const的指针;将const变量的地址赋给指向const的指针;将const的地址赋给常规指针。这里面,第四种是不可行的,其他都可行。

    4. 将指针参数声明为指向常量数据的指针有两条理由:a. 这样可以避免由于无意间修改数据而导致的编程错误;b. 使用const使得函数能够处理const和非const实参,否则将只能接受非const数据。如果条件允许,则应将指针形参声明为指向const的指针。

函数和C-风格字符串

  • 将字符串作为参数时意味着传递的是地址,但可以使用const来禁止对字符串参数进行修改。
  • C-风格字符串有内置的结束字符,这意味着不必将字符串长度作为参数传递给函数,而函数可以使用循环依次检查字符串中的每个字符,直到遇到结尾的空值字符为止。

函数和结构

涉及到函数传递时,结构变量的行为更接近于基本的单值变量:

  • 可以将一个结构赋给另一个结构;
  • 可以按值传递结构,就像普通变量那样;在这种情况下,函数将使用原始结构的副本;函数也可以返回结构;但这样有一个缺点,如果结构非常大,则复制结构将增加内存要求,降低系统运行的速度;
  • 也可以传递结构的地址,用指针来访问结构的地址;与数组名就是数组第一个元素的地址不同的是,结构名只是结构的名称,要获得结构的地址,必须使用地址运算符&
  • 另外,C++还使用&表示引用变量,按引用传递也是特别重要的一种方式。

递归

函数指针

总结

函数是C++的编程模块。要使用函数,必须提供定义和原型,并调用该函数。函数定义是实现函数功能的代码;函数原型描述了函数的接口; 传递给函数的值的数目和种类以及函数的返回类型,函数调用使得程序将参数传递给函数,并执行函数的代码。

在默认情况下,C++函数按值传递参数。这意味着函数定义中的形参是新的变量,它们被初始化为函数调用所提供的值。因此,C++函数通过使用拷贝,保护了原始数据的完整性。

C++将数组名参数视为数组第一个元素的地址。从技术上讲,这仍然是按值传递的,因为指针是原始地址的拷贝,但函数将使用指针来访问原始数组的内容。当且仅当声明函数的形参时,下面两个声明才是等价的:

typeName arr[];
typeName * arr;

这两个声明都表明,arr是指向typeName的指针,但在编写函数代码时,可以像使用数组名那样使用arr来访问元素:arr[i]。即使在传递指针时,也可以将形参声明为const指针,来保护原始数据的完整性。由于传递数据的地址时,并不会传输有关数组长度的信息,因此通常将数组长度作为独立的参数来传递。另外,也可传递两个指针(其中一个指向数组开头,另一个指向数组末尾的下一个元素),以指定一个范围,就像STL使用的算法一样。

C++提供了3种表示C-风格字符串的方法:字符数组、字符串常量和字符串指针。它们的类型都是char*char指针),因此被作为char*类型参数传递给函数。C++使用空值字符(\0)来结束字符串,因此字符串函数检测空值字符来确定字符串的结尾。

C++还提供了string类,用于表示字符串。函数可以接受string对象作为参数以及将string对象作为返回值。string类的方法size()可用于判断其存储的字符串的长度。

C++处理结构的方式与基本类型完全相同,这意味着可以按值传递结构,并将其用作函数返回类型。然而,如果结构非常大,则传递结构指针的效率将更高,同事函数能够使用原始数据。这些考虑因素也适用于类对象。

C++函数可以是递归的,也就是说,函数代码中可以包括对函数本身的调用。

C++函数名与函数地址的作用相同。通过将函数指针作为参数,可以传递要调用的函数的名称。

C++ Primer Plus学习(七)——函数简介相关推荐

  1. 整理:C primer plus 学习笔记

    前言:简单看了一遍C Primer Plus, 整理了一下,因为时间比较少,自己理解地比较肤浅,所以第一版比较简陋. 假期的时候应该会有时间再整理一下.------2018/11/5 2019/1/2 ...

  2. C++ Primer Plus 学习笔记(第 4 章 复合类型)

    C++ Primer Plus 学习笔记 第 4 章 复合类型 数组 数组(array)是一种数据格式,能够存储多个同类型的值. 要创建数组,可使用声明语句.数组声明应指出以下三点: 存储在每个元素的 ...

  3. c语言实验七 函数实验报告,C语言实验七函数实验报告.doc

    C语言实验七函数实验报告 C语言程序设计 实 验 报 告 实验题目 实验七 函数 实验目的 掌握函数定义的方法: 掌握函数实参与形参的对应关系,以及值传递的方式. 掌握函数的嵌套调用和递归调用的方法: ...

  4. TypeScript基础入门 - 函数 - 简介

    2019独角兽企业重金招聘Python工程师标准>>> 转载 TypeScript基础入门 - 函数 - 简介 项目实践仓库 https://github.com/durban89/ ...

  5. Python之sklearn:LabelEncoder函数简介(编码与编码还原)、使用方法、具体案例之详细攻略

    Python之sklearn:LabelEncoder函数简介(编码与编码还原).使用方法.具体案例之详细攻略 目录 LabelEncoder函数的简介(编码与编码还原) Methods LabelE ...

  6. DL:深度学习(神经网络)的简介、基础知识(神经元/感知机、训练策略、预测原理)、算法分类、经典案例应用之详细攻略

    DL:深度学习(神经网络)的简介.基础知识(神经元/感知机.训练策略.预测原理).算法分类.经典案例应用之详细攻略 目录 深度学习(神经网络)的简介 1.深度学习浪潮兴起的三大因素 深度学习(神经网络 ...

  7. 如何利用《C++ Primer》学习C++?

    <C++ Primer>作为久负盛名的C++经典教程,丰富的教学辅助内容.精心组织的编程示范,无论是初学者入门,或是中.高级程序员提升,都是不容置疑的首选. 一本好书只有读过才有价值,然而 ...

  8. OpenCV与图像处理学习七——传统图像分割之阈值法(固定阈值、自适应阈值、大津阈值)

    OpenCV与图像处理学习七--传统图像分割之阈值法(固定阈值.自适应阈值.大津阈值) 一.固定阈值图像分割 1.1 直方图双峰法 1.2 OpenCV中的固定阈值分割 二.自动阈值图像分割 2.1 ...

  9. PyTorch框架学习七——自定义transforms方法

    PyTorch框架学习七--自定义transforms方法 一.自定义transforms注意要素 二.自定义transforms步骤 三.自定义transforms实例:椒盐噪声 虽然前面的笔记介绍 ...

最新文章

  1. webpack 使用别名(resolve.alias)解决scss @import相对路径导致的问题
  2. Spring中AOP相关的API及源码解析,原来AOP是这样子的
  3. 【MM】需求类型清单
  4. html中表单元素_HTML中的表单元素
  5. 11-散列3 QQ帐户的申请与登陆 (25 分)
  6. Docker中搭建FastDFS文件系统(多图)
  7. 编解码标准H264 与 AVS 变换矩阵比较
  8. 计算机 旧词新说_如何使旧计算机再次有用
  9. [Web Chart系列之一(续)]Web端图形绘制SVG,VML, HTML5 Canvas 简单实例
  10. 月薪11.5K 土木人零基础转行软件测试工程师,他都经历了什么?
  11. OpenGL调用GPU(七)
  12. vs2005新建项目中没有ASP.NET WEB应用程序的解决方法
  13. Linux之kill命令
  14. 视频,多媒体本地化总结
  15. 软件工程导论学习总结
  16. 88年的世界杯历史,用Python带你回顾!
  17. ubuntu GStreamer + QT多媒体播放器开发(二)
  18. 移动端touch事件影响界面click/超链接事件无法点击
  19. Mac如何录屏 同时录内置声音
  20. dataframe两个表合并_DataFrame踩坑整理(一)

热门文章

  1. bzoj 2351: [BeiJing2011]Matrix(二维Hash)
  2. bzoj 3503: [Cqoi2014]和谐矩阵(高斯消元)
  3. bzoj 1622: [Usaco2008 Open]Word Power 名字的能量
  4. bzoj 1670: [Usaco2006 Oct]Building the Moat护城河的挖掘(凸包)
  5. opencv 寻找图中的corners 利用自带 Shi-Tomasi Corner Detector 实现
  6. javascript学习之利用方向键控制div模块的移动
  7. [Python] numpy.ndenumerate() 获得一对数组坐标和值
  8. 2020 各大厂分享ppt
  9. 深度学习:文本检测数据集整理
  10. 汇编三星题目:一个有符号字数组以0为结束标志,编程求这个数组的最大值、 最小值、平均值