• 《C++ primer plus》第7章:函数——C++的编程模块


    复习函数的基本知识

    C++对于返回值的类型有一定的限制:不能是数组,但可以是其他任何类型——整数、浮点数、指针,甚至可以是结构和对象(有趣的是,虽然C++函数不能直接返回数组,但可以将数组作为结构或对象组成部分来返回)。

    在函数声明的参数列表中,可以包括变量名,也可以不包括。原型中的变量名相当于占位符,因此不必与函数定义中的变量名相同。

    在C++中,括号为空与在括号中使用关键字 void 是等效的——意味着函数没有参数。

    在 C++ 中,不指定参数列表时应使用省略号:如:
    void say_bye(…);
    通常,仅当与接受可变参数的 C 函数(如printf()) 交互时才需要这样做。

    静态类型检查,编译阶段,检查函数参数类型是否正确,并进行可以进行的类型转换。

    函数参数和按值传递

    声明中的变量名不必与定义中的变量名相同,而且可以省略。

    一句话总结,按值传递就是函数自身会创建以形参名为名的变量来使用,并不会修改给函数传值的实参的值。

    函数和数组

    函数如何用指针来处理数组?
    在大多数情况下,C++ 将数组名视为指针,但有一些例外,首先,数组声明使用数组名来标记存储位置;其次,对数组名使用 sizeof 将得到整个数组的长度(以字节为单位),第三,将地址运算符&用于数组名时,将返回整个数组的地址,对它加1是加整个数组占用的字节数,而不是单个元素的字节数。

    int sum_arr(int arr[], int n);

    int sum_arr(int * arr, int n);

    用 int * arr 替换了 int arr[],这两个函数头都是正确的,在C++中,仅在函数参数列表中,int *arr 和 int arr[]才是相同的。它们都意味着 arr 是一个int指针。然而,数组表示法( int arr[] ) 提醒用户,arr 不仅指向int,还指向int数组的第一个int。
    当指针指向数组的第一个元素时,一般使用数组表示法;而当指针指向一个独立的值时,一般使用指针表示法。

    但在其它上下文中,并不能用 int arr[]来声明一个指针。

    传递常规变量时,函数将使用该变量的拷贝,但传递数组时,函数将使用原来的数组。实际上,这种区别并不违反C++按值传递的原则,传递数组时仍然传递了一个值,这个值是地址,这个值被赋给了一个新的变量,但是这个值(也就是这个地址)指向的就是原来的数组。

    注意,函数参数里使用int arr[],在函数内对arr使用sizeof,得到的是指针变量的长度,而不是整个数组的长度。这也是必须显示传递数组长度,而不是在函数内部使用sizeof的原因;指针本身并没有指出数组的长度。

    注意,为将数组类型和元素数量告诉数组处理函数,请通过两个不同的参数来传递它们:
    void fillArray(int arr[], int size);
    而不要试图使用方括号表示法来传递数组长度:
    void fillArray(int arr[size]);这是错误的。

    void show_array(const double ar[], int n);
    const double arr[],表明,指针ar指向的是常量数据,这意味着不能使用arr修改该数据。但这并不意味着原始数组必须是常量,而只是意味着不能在show_array()函数中使用 ar 来修改这些数据。

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

    C++禁止将const变量的地址分配给非const指针。(如果非要这样做,可以使用强制类型转换来突破这种限制)

    注意
    const int * ps
    int * const ps
    两者的区别是,前者表示指针指向的内容不能被修改,后者表示指针本身不能被修改

    函数和二维数组

    int sum( int (*ar)[4], int size);
    int sum( int ar[] [4], int size);

    使用方式

    ar[r][c];

    *(*(ar+r)+c)

    函数和C-风格字符串

    C-风格字符串由一系列字符组成,以空字符结尾。有关函数的数组的规则也适用于字符串函数。但字符串还有一些特殊的规则。

    假设要将字符串作为参数传递给函数,则表示字符串的方式有三种:

    • char数组;
    • 用括号引起的字符串常量(也称字符串字面值);
    • 被设置为字符串的地址的 char 指针
      但上述 3 种选择的类型都是 char 指针(准确地说是 char*),因此可以将其作为字符串处理函数的参数

    可以说是将字符串作为参数来传递,但实际传递的是字符串第一个字符的地址。这意味着字符串函数声明将其表示字符串的形参声明为 char* 类型。

    C-风格字符串与常规 char 数组之间的一个重要区别是,字符串有内置的结束字符,这意味着不必将字符串长度作为参数传递给函数,而函数可以使用循环以此检查字符串中的每个字符,指导遇到结尾的空字符为止。

    一种处理字符串中字符的标准方式:

    while(*str){
    	statements;
    	str++;
    }
    
    • 1
    • 2
    • 3
    • 4

    函数和结构

    为结构编写函数比为数组编写函数要简单得多,虽然结构变量和数组一样,都已存储多个数据项,但在涉及到函数时,结构变量的行为更接近于基本的单值变量。使用结构来编程时,最直接的方式是像处理基本类型那样来处理结构:也就是说,将结构作为参数传递,并在需要时将结构用作返回值使用。

    按值传递;传递地址,使用指针来访问结构的内容;按引用传递。

    按值传递:当将一个实参传递给函数时,结构的内容会被拷贝到形参中,函数随后使用拷贝完成工作。

    使用指针传递的时候可以把要修改的结构的地址作为一个参数,传递给函数。

    函数和 string 对象

    除了getline()外,程序一般像对待内置类型一样对待string对象。

    函数和 array 对象

    如果需要使用array类,要包含头文件array,而名称array位于名称空间std中。

    std::array expenses;

    使用指针来操作array的时候要注意运算优先级的问题;
    (*pa)[i]才能表示array的第i项;

    递归

    从函数体内调用函数本身的地方开始,调用者暂停运行,执行被调用者代码。

    递归的方式可用于分而治之的策略。

    函数指针

    与数据项相似,函数也有地址。函数的地址是存储其机器语言代码的内存的开始地址。通常,这些地址对用户而言,既不重要,也没有什么用处,但对程序而言,却很有用。例如,可以编写将另一个函数的地址作为参数的函数。这样第一个函数将能够找到第二个函数,并运行它。与直接调用另一个函数相比,这种方法很笨拙,但它允许在不同的时间传递不同函数的地址,这意味着可以在不同的时间使用不同的函数。

    函数指针的基础知识

    1. 获取函数地址
      使用函数名(后面不跟参数)即可。

    2. 声明函数指针
      double pam(int);
      double (*pf) (int);

      void estimate(int lines, double (*pf) (int));
      estimate(50, pam);
      显然,使用函数指针时,比较棘手的是编写原型,而传递地址则非常简单。

    3. 使用指针来调用函数
      double pam(int);
      double (*pf) (int);
      pf = pam;
      double x = pam(4);
      double y = (*pf)(5);
      实际上,C++ 也允许像使用函数名那样使用 pf:
      double y = pf(5);
      第一种格式较为复杂,但是给出了强有力的提示——代码正在使用函数指针。

    注意这里和普通变量不同,对函数指针来说 使用(*pf) 和pf作为函数名都是可以的,两者是等价的,而普通变量的指针不是这样。

    深入探讨函数指针

    注意以指针为元素的数组,和指向数组的指针在表示上的区别,
    []的优先级比*高

    函数指针可以在声明的时候初始化,方法是 声明时像赋值语句一样赋值(赋值的内容是函数名)

    注意使用 auto

    还可以使用 typedef 来简化

  • 相关阅读:
    Windows——实现exe自删除
    2022杭电多校第三场 Two Permutations (dp, 哈希)
    基于BERT+BiLSTM+CRF模型与新预处理方法的古籍自动标点
    三刷操作系统之一文带你搞懂FreeRTOS——信号量
    矩阵求导详解
    Openwrt_树莓派B+_Wifi中继
    linux离线源码安装Redis
    001图机器学习与图神经网络简介
    手把手怎么把照片修复高清,p图小白也能轻松上手
    云盘文件批量分享脚本
  • 原文地址:https://blog.csdn.net/weixin_40064300/article/details/128012488