C++回炉之_C++PrimerPlus_第七章 函数 -- C++的编程模块(二)

函数和二维数组

  • 使用二维数组作为参数, 必须指定第二维的维数 – 元素的类型

    • 表示arr为一个数组名,而数组的每一个元素也是一个数组, 由2个int组成
    • 即arr的类型是指向由2个int组成的数组的指向
    • 其中的括号必不可少,因为 int *arr[2]表示由2个指向int的指针组成的数组 – 函数参数不能为数组
    • 另一种格式 – int sum(int arr[][2], int n);二者含义相同
    • 两个原型都指出, arr是指针而非数组,这是至关重要的一点
    int sum(int (*arr)[2], int n) {
        int res = 0;
        for(int i = 0; i < n; ++i) 
            for(int j = 0; j < 2; ++j) res += arr[i][j];
        return res;
    }
    
    int a[3][2] = { {1, 2}, {3, 4}, {5, 6} };
    cout << sum(a, 3) << endl;
    

函数和C风格字符串

  • 将字符串作为参数

    • 使用 char* (指向char类型的指针) – void show_str(const char* str);
    • 也可使用 void show_str(const char str[]);
    void show_str(const char* str) {
        while (*str) {
            cout << *str;
            ++str;
        }
        cout << endl;
    }
    
    char str[] = "hello world";
    show_str(str);
  • 将字符串作为返回值

    • 返回字符串的地址即可
    
    #include <iostream>
    
    using namespace std;
    
    char* build_str(char ch, int n) {
        char* p_str = new char[1+n];        // 虽然p_str在函数结束时会被释放
        p_str[n] = '\0';
        while(n-- > 0) p_str[n] = ch;
        return p_str;                       // 但 new 的内存还在
    }
    
    int main() {
    
        char* str = build_str('d', 10);
        cout << str << endl;
        delete [] str;                      // 所以需要手动delete此内存块
    
    }
    

函数和结构体

  • 像对待基本数据类型一样对待结构体即可

    
    #include <iostream>
    
    using namespace std;
    
    struct pos {
        int x, y;
    };
    
    pos sum_pos(pos a, pos b) {
        pos res;
        res.x = a.x + b.x;
        res.y = a.y + b.y;
        return res;
    }
    
    int main() {
        pos m{1, 2};
        pos n = {3, 4};
    
        pos r = sum_pos(m, n);
        cout << r.x << " " << r.y << endl;
    
    }
    
  • 传递结构体的地址 – 以节省时间和空间

    pos* sum_pos(const pos* a, const pos* b) {
        pos* res = new pos;
        res->x = a->x + b->x;
        res->y = a->y + b->y;
        return res;
    }
    
    pos* r = sum_pos(&m, &n);
    cout << r->x << " " << r->y << endl;
    delete r;
    
    • 传递地址的话可以将结果作为指针直接放在参数中,而不用返回值
    void sum_pos(const pos* a, const pos* b, pos* res) {
        res->x = a->x + b->x;
        res->y = a->y + b->y;
    }
    pos r;
    sum_pos(&m, &n, &r);
    cout << r.x << " " << r.y << endl;
  • string对象, array对象 等,都可看作基本类型, 像结构体一样在函数中使用

递归函数

  • 除了main函数外,函数都可以调用自身
  • 一个递归函数必须有递归调用的终点,否则将会无限调用下去
  • 每一个递归过程中的函数都是独立的
  • 递归的过程与普通函数调用的过程类似
  • 只需将函数里对自己本身的调用也看作是对其他函数的调用(只不过功能相同)即可

    // 求n的阶乘
    int factorial(int n) {
        if(n == 1) return 1;                // 循环终止条件
        return n * factorial(n-1);          // 递归
    }
    // 快速排序 -- O(nlogn)
    void quick_sort(int a[], int L, int R) {  //[L, R]
        if(L >= R) return;                                  // 循环终止条件
        int x = L, y = R, p = a[L];
        while(x < y) {                                      //最后找到的x即为划分地
            while(x < y && a[y] >= p) --y; a[x] = a[y];     //y向左到比p小的,移到左边去
            while(x < y && a[x] <= p) ++x; a[y] = a[x];     //x向右到比p大的,移到右边去
        }//end 划分
        a[x] = p;
        quick_sort(a, L, x-1); quick_sort(a, x+1, R);       // 递归
    }
    
    int a[] { 5, 3, 2 ,1, 4};
    quick_sort(a, 0, 4);
    for(int i = 0; i < 5; ++i) cout << a[i] << endl;

函数指针初探

  • 函数的地址 – 函数名即为函数的地址(不带括号)
  • 声明函数指针 – 使用(*pf) 替代函数名

    bool cmp(int a, int b);
    bool (*p_cmp)(int a, int b);
    • 由于 (*p_cmp)cmp 等价,所以 (*p_cmp) 也是函数,则 p_cmp 就是函数指针了
    • 不加括号的话 bool *p_cmp(int a, int b); 为一个返回bool*的函数,而非函数指针
  • 给函数指针赋值

    • 赋值的条件是函数参数和返回类型与指针都一致
    p_cmp = cmp
  • 使用函数指针调用函数

    • 可以使用(*pf)调用,也可以直接使用指针名作为函数名调用 – amazing
    cout << (*p_cmp)(1, 2) << endl;
    cout << p_cmp(1, 2) << endl;
  • 一个短而有力的例子

    
    #include <iostream>
    
    using namespace std;
    
    bool cmp(int a, int b) { return a > b; }
    bool cmp_2(int a, int b) { return a <= b; }
    
    //返回两个数的较大值 -- 自定义比较规则
    int max_i(int a, int b, bool (*p_cmp)(int a, int b)) {
        if(p_cmp(a, b)) return a;
        else return b;
    }
    
    int main() {
        cout << max_i(1, 2, cmp) << endl;
        cout << max_i(1, 2, cmp_2) << endl;
    }
    

    输出结果为

    2
    1

  • 更复杂的用法

    • 函数指针的数组

      int (*p_s[3])(int, int);
      • [] 的优先级高于 *, 故(*p_s[3])表示一个包含三个指针的数组
    • 指向 函数指针数组 的指针

      int (*(*p_ps)[3])(int, int);    // 有些小变态
      • p_s替换成 (*p_ps)即可
      • 加括号表示p_ps是一个指针,它指向一个包含3个元素的数组
    • 可使用auto 或typedef简化代码

      • auto 只能用于单值初始化,而不能用于初始化表
      • 使用typedef 可声明函数指针的别名 – 使代码更容易理解
      typedef int (*p_fun)(int, int);
      p_fun p1 = s1;
      p_fun pa[3] = {s1, s2, s3};
      p_fun (*pd)[3] = &pa;
    • 一个短而有力例子

      
      #include <iostream>
      
      using namespace std;
      
      int s1(int a, int b) { return a + b + 0; }
      int s2(int a, int b) { return a + b + 1; }
      int s3(int a, int b) { return a + b + 2; }
      
      int main() {
          // 函数指针的数组
          int (*p_s[3])(int, int) = { s1, s2, s3};
      
          for(int i = 0; i < 3; ++i) {
              cout << p_s[i](1, 2) << " ";        // 等价于 cout << (*p_s[i])(1, 2) << endl;
          }
      
          // 指向 函数指针数组 的指针
          // 也可用 auto p_ps = &p_s; 简化
          int (*(*p_ps)[3])(int, int) = &p_s;
          for(int i = 0; i < 3; ++i) {
              cout << (*p_ps)[i](1, 2) << " ";    // 等价于 cout << (*(*p_ps)[i])(1, 2) << endl;
          }
      
      }
      
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值