• C++学习基础十六-- 函数学习笔记


    C++ Primer 第七章-函数学习笔记


    一步一个脚印、循序渐进的学习。


     一、参数传递

    1. 每次调用函数时,都会重新创建函数所有的形参,此时所传递的实参将会初始化对应的形参。
    • 「如果形参是非引用类型,则复制实参的值来初始化形参;如果形参是引用类型,则形参只是实参的别名。」
    • 「非引用形参表示对实参的局部副本,函数内修改此类型形参时仅仅改变局部副本的值,一旦函数执行结束,这些局部变量的值就没有了,因此不影响实参的值。」
    • 「如果函数参数为指针,同样形参是实参的副本,修改形参指针的值不影响实参,但是如果修改形参指针所指向的值则会影响实参。」
     1 void reset1(int *p)  
     2 {
     3     *p = 0;//修改形参所指向的值,则实参所指向的值也会改变,变为0  
     4 }  
     5 
     6 void reset2(int *p)
     7 {
     8     p = 0;//仅修改形参值,不影响实参值,即实参还是原来的地址,而形参的地址变为0
     9 }
    10 
    11 void main()
    12 {
    13     int i = 2;
    14     reset1(&i);
    15     printf("i = %d 
    ",i);// i = 0
    16     
    17     i = 2;
    18     reset2(&i);
    19     printf("i = %d 
    ",i); // i = 2
    20 }
    • 「如果想要保护指针指向的值,则需要将指针定义为const,表示当前指针所指向的值可读不可写。」
    1 void reset3(const int *p)
    2 {
    3     p = 0;//ok
    4     *p = 0;//error,不允许修改p所指向的值
    5
    1. 可以用非const指针初始化const指针,但不允许使用const指针初始化非const指针。例如:
    int i = 2;
    const int *p1 = &i;//ok, 非const指针初始化const指针
    int p2 = p1;//error, 不能用const指针初始化非const指针,报语法错误 
    1. 当函数的参数是非引用(或非指针)非const的类型时,在调用该函数时,实参既可以是const类型的,也可以是非const类型的。
    1. 如果需要在函数内部修改实参值,则需要将形参定义为引用或者指针。

    2. const修饰变量,表示该变量不可修改,这是对于基本数据类型而言。对于指针来说,有两种情况:

    1 int num = 2;
    2 int num2 = 30;
    3 const int *p1 = #// *p1 = 20 不允许修改
    4 int * const p2 = #// p2 = &num2 不允许
    • 第三行这种写法表示p1所指向的值是const类型的,不允许修改其所指向的值。
    • 第四行这种写法表示p2这个指针是const类型的,不允许给该指针重新赋值。
    1. 指向指针的引用
      写法:int *&p1
      从右向左理解,表示p1是一个引用,与该引用绑定的是一个int型的指针。
      这种写法一般常用函数的参数,

           举例说明:实现一个函数,该函数的功能是交换两个参数的值。
           这有三种方法:

    • 第一种方法:传递int型指针

            这种情况下,形参复制实参的值,此时两者的地址值相同,即指向相同的对象。此时只是修改了指针所指向地址中的值,而并未改变指针值。

     1 void TransNums(int *p1, int *p2)
     2 {
     3     int nTmp = (*p1);
     4     *p1 = *p2;
     5     *p2 = nTmp;
     6 }
     7 
     8 void main()
     9 {
    10     int num = 10;
    11     int *p2 = #
    12     int numP3 = 30;
    13     int *p3 = &numP3;
    14     
    15     printf("未交换-指针值:p2 = %d, p3 = %d num = %d  numP3 = %d
    ", *p2, *p3,num,numP3);
    16     TransNums(p2, p3);
    17     printf("交换-指针的值:p2 = %d, p3 = %d num = %d  numP3 = %d
    ", *p2, *p3,num,numP3);
    18 }

      打印结果:

      未交换-指针值:p2 = 10, p3 = 30 num = 10 numP3 = 30
      交换-指针的值:p2 = 30, p3 = 10 num = 30 numP3 = 10

      「表示修改了指针所指向的值,而并未改变指针」

    • 第二种方法:传递int性引用

      形参是实参的别名,等同于实参。

     1 void TransNumsRef(int &num1, int &num2){
     2     int nTmp = num1;
     3     num1 = num2;
     4     num2 = nTmp;
     5 }
     6 
     7 void main()
     8 {
     9     int num = 10;
    10     int numP3 = 30;
    11     
    12     printf("未交换-实参值:num = %d, numP3 = %d
    ", num, numP3);
    13     TransNumsRef(num, numP3);
    14     printf("交换-实参的值:num = %d, numP3 = %d
    ", num, numP3);
    15 }

      打印结果:

      未交换-实参值:num = 10, numP3 = 30
      交换-实参的值:num = 30, numP3 = 10

    • 第三种方法:传递指针引用参数

      此时形参为引用,指向指针,这种情况下修改了指针,即指针的值(或地址)改变了

     1 void TransNumsPRef(int *&p1, int *&p2)
     2 {
     3     int *pTmp = p1;
     4     p1 = p2;
     5     p2 = pTmp;
     6 }
     7 
     8 void main()
     9 {
    10     int num = 10;
    11     int *p2 = #
    12     int numP3 = 30;
    13     int *p3 = &numP3;
    14     printf("未交换-指针引用值:p2 = %d, p3 = %d  num = %d  numP3 = %d
    ", *p2, *p3,num,numP3);
    15     TransNumsPRef(p2, p3);
    16     printf("交换-指针引用的值:p2 = %d, p3 = %d num = %d  numP3 = %d
    ", *p2, *p3,num,numP3);
    17 }

      打印结果:

      未交换-指针引用值:p2 = 10, p3 = 30 num = 10 numP3 = 30
      交换-指针引用的值:p2 = 30, p3 = 10 num = 10 numP3 = 30

    1. 几种常见的表示形式:
    1 int &arr[10]--- 表示arr是一个引用数组,即arr一个数组,数组的每个元素是int类型的引用
    2 int (&arr)[10]--表示arr是一个数组的引用,数组的每个元素是int类型变量
    3 int *arr[10]----表示arr是一个指针数组,即arr是一个数组,每个元素是一个int型指针
    4 int (*arr)[10]--表示arr是一个数组的指针,即该指针指向一个数组,数组的每个元素是int变量,等同于int (arr*)[10]

    二、函数声明

    1. 默认实参
      声明一个函数时,我们可以给定形参的默认值,这种用法就是默认实参。如果有一个或多个形参具有默认实参,那么它后面的所有形参都必须有默认实参。
      一般而言,具有默认实参的形参放在参数列表的后面。

    2. 应该在函数声明中提供默认实参。如果在函数定义的形参列表中提供默认实参,那么只有在包含该函数定义的源文件中调用,其默认实参才有效。

    三、内联函数

    1. 优点:
    • 减少函数调用的开销。将函数定义为内联函数,就是在程序中每个调用点上“内联的”展开。
    1. 注意事项:
    • 不同于其他函数,内联函数定义必须在头文件中实现。

    四、重载函数

    1. 重载函数:函数名相同,参数列表不同的函数。

    2. 函数名与参数列表完全相同,返回值类型不同的不能成为函数重载。即函数重载不能依赖于返回值类型。

    3. 重载和const参数:仅当形参是引用或指针时,形参是否为const才有影响。

    4. 几种情况并举例说明:

    • 基于函数的引用形参是否为const实现函数重载
    1 void lookat(int &a);
    2 void lookat(const int &a);//新函数,即函数重载

    「如果形参为非const引用,则函数调用时,不能将const类型的实参传递过来;如果传递了const对象,则必须调用带有const形参的函数。」
    「如果形参为const引用,则函数调用时,既可以传递const对象,也可以传递非const对象。」

    • 基于函数的指针形参是否指向const对象实现函数重载
    1 void func(int *p);
    2 void func(const int *p);//新函数,指向const对象

    「如果形参为指向const对象的指针,则函数调用时,实参既可以是指向const对象的指针,也可以是指向非const对象的指针。」
    「如果两个函数仅在指针形参是否指向const对象不同,则指向非const对象的指针形参对于指向非const对象的实参来说是最佳匹配。」

    • 不能基于指针本身是否是const类型重载函数
    1 void foo(int *p);
    2 void foo(int * const p);//重复声明
  • 相关阅读:
    Uboot的串口下载文件命令:loads / loadb / loady
    U-Boot中关于TEXT_BASE,代码重定位,链接地址相关说明
    u-boot-2014.04分析
    Spring MVC + Java 多文件上传及多文件中转上传
    Java 文件上传中转
    backdrop-filter 和filter 写出高斯模糊效果 以及两者区别
    解读浮动闭合最佳方案:clearfix
    JavaScript ES6中export及export default的区别
    webpack配置常用loader加载器
    chrome jsonView插件安装
  • 原文地址:https://www.cnblogs.com/calence/p/7441911.html
Copyright © 2020-2023  润新知