函数(一) (学习笔记)

函数部分知识大致已经掌握,此为复习,因此记录学习过程从简。

1.函数基础

        一个典型的函数定义包括以下几个部分:返回类型、函数名称、由0个或者多个形参组成的列表以及函数体。
1.1 局部对象

       **自动对象**
        只存在于块执行期间的对象称之为自动对象。形参为一种自动对象,函数开始时为形参申请存储空间,而
    函数终止,则形参被销毁。

       **局部静态对象**
        令局部变量的生命周期贯穿函数调用及之后的时间,可将局部变量定义为static类型,该对象在程序终止时
    才会被销毁。

 1.2 函数声明

       **在头文件中进行函数声明**

 1.3 分离式编译 

       **编译和链接多个源文件**

2.参数传递

 每次调用函数时都会重新创建它的形参,并用传入的实参对形参进行初始化。初始化形参的机理与初始化变量一样。
 当实参的值被拷贝给形参时,形参和实参是两个相互独立的对象。

 2.1 传值参数

 当初始化一个非引用类型的变量时,初始值被拷贝给变量,此时,对变量的改动不会影响初始值。

 **指针形参**
    指针的行为和其他非引用类型一样,当执行指针拷贝操作时,拷贝的是指针的值。在C++语言中,建议使用引用类型
的形参替代指针。

2.2 传引用参数

 **使用引用避免拷贝**  : 如果函数无须改变引用形参的值,最好将其声明为常量引用。
 例:

  bool isShorter(const string &s1, const string &s2)
  {
     return s1.size() < s2.size();
  }

   **使用引用形参返回额外信息**  : 若函数需要多个返回值,引用形参可以做为函数的返回值。
   例:
    string::size_type find_char (const string &s, char c,string::size_type &occurs)
       { 
          auto ret = s.size();
          occurs = 0;
          for (decltype(ret) i =0;i!=s.size();++i)
          {
             if (s[i] == c)
             {
                if (s[i] == s.size())
                   ret =i;      //记录c第一次出现的位置
                   ++occurs;    //将出现的次数加1
             }
          }
          return ret;       //出现次数通过occurs隐式地返回
       }
   2.3 const形参和实参

   **顶层const**: 顶层const表示指针本身是一个常量,底层const表示指针指向的对象是一个常量。

   int i =0;
   int *const p1 = &i;    //不能改变p1的值,这是一个顶层const
   const int ci =42 ;     //不能改变ci的值,这是一个顶层const
   cosnt int *p2 = &ci;   //允许改变p2的值,这是一个底层const
   const int *const p3 = p2; //靠右的const是顶层const,靠左的是底层const
   const int &r = ci;     //用于声明引用的const都是底层const

   2.4 数组形参

   数组的性质是:1.不允许拷贝数组;2.使用数组时(通常)会将其转换成指针。
   以下三个函数等价:
   void print (const int*);
   void print (const int[]);
   void print (const int[10]);

   如果我们传给print函数的是一个数组,则实参自动地转换成指向数组首元素的指针,数组的
   大小对函数的调用没有影响。

   **管理数组实参**
   第一种方法是要求数组本身包含一个结束标记: 
    void print (const char *cp)
       { 
          if (cp)     //若cp不是一个空指针
              while (*cp)  //只要指针所指的字符不是空字符
                 cout << *cp++; //输出当前字符并指针向前移动一个位置
       }
   第二种方法是传递指向数组首元素和尾后元素的指针:
    void print (const int *beg,const int *end)
       {
          while (beg != end)
             cout << *beg++ <<endl;  //输出当前元素并将指针向前移动一个位置
       }
  第三种方法是专门定义一个表示数组大小的形参
    void print (const int ia[],size_t size)
      {
         for (size_t i=0;i !=size; i++)
         {
            cout <<ia[i]<<endl;
         }
      }
  当函数不需要对数组元素执行写操作的时候,数组形参应该是指向const的指针。
     void print (int (&arr)[10])    //&arr两端的括号必不可少,arr是具有10个整数的整型数组的引用
      {
         for (auto elem : arr)  
         cout << elem << endl;
      }
 当将多维数组传递给函数时,真正传递的是指向数组首元素的指针。因为我们处理的是多维数组(数组的数组),
 所以首元素本身是一个数组,指针就是指向数组的指针。数组的第二维(以及后面的所有维度)的大小都是数组
 类型的一部分,不能省略:
 //matrix指向数组的首元素,该数组的元素是由10个整数构成的数组
 void print (int (*matrix)[10],int rowsize) {}
 等价于:
 void print (int matrix[][10],int rowsize) {} 

 2.5 含有可变形参的函数

 如果函数的实参数量未知但是全部实参的类型都相同,我们可以使用initializer_list类型的实参。 
 initializer_list是一种模板类型,定义其对象时,必须说明列表中所含元素的类型:
 initializer_list<string> ls ; initializer_list <int> li;

 我们使用如下的形式编写输出错误信息的函数,使其可以作用于可变数量的实参:
     void error_msg (initializer_list <string> il)
     {
        for (auto beg = il.begin();beg != il.end();++beg)
        {
           cout << *beg <<"";
           cout << endl;
        }
     }
如果想向initializer_list形参中传递一个值的序列,则必须把序列放在一对花括号内: 
 // expcted 和 actual 是string 对象
    if (expected != actual)
    { 
       error_msg ({"functionX",expected,actual});
       error_msg ({"functionX","okay"});
    }
含有initializer_list形参的函数也可以同时拥有其他形参。  
 void error_msg (ErrCode e,initializer_list <string> il)
    {
       cout << e.msg() <<":";
       for (const auto &elem : il)
       cout << elem << " ";
       cout << endl;
    }
 调用上面的函数,其表达式为
     if (expected != actual)
     error_msg(ErrorCode(42),{"functionX",expected,actual});
     else
     error_msg(ErrCode(0),{"functionX","okay"});

3.返回类型和return语句

 无返回值函数、有返回值函数、递归
 3.3 返回数组指针

 int arr[10]; //arr是一个含有10个整数的数组
 int *p1[10]; //p1是一个含有10个指针的数组
 int (*p2)[10]; //p2是一个指针,它含有10个整数的数组

 返回数组指针的函数形式如下图所示:
 Type (*function(parameter_list)) [dimension]

 例: int (*function(int i))[10];

 声明的含义:func(int i) 表示调用func函数需要一个int类型的实参
            (*func(int i)) 表示我们可以对函数调用的结果执行解引用操作
            (*func(int i)) [10] 表示解引用func的调用将得到一个大小是10的数组
            int (*func(int i)) [10] 表示数组中的元素是int类型     

 **使用decltype**
 int odd[] = {1,3,5,7,9};
 int even[] = {0,2,4,6};
 //返回一个指针,该指针指向含有5个整数的数组
 decltype(odd) *arrPtr(int i)
 {
    return ( 1 % 2) ? &odd : &even;  //返回一个指向数组的指针
 }

4.函数重载

5.内联函数和constexpr函数

6.函数指针

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值