• C++函数的参数传递机制以及参数的类型选择


    C++primer之函数的参数传递以及参数的类型



    一:函数的基本知识

    (1)      函数要素:返回类型,函数名字,形参(参数之间用逗号隔开)

    (2)      函数调用机制:我们通过调用运算符来执行函数,其中运算符就是括号

    (3)      当我们调用函数时,主调函数被暂停执行,被调函数开始执行,当被调函数遇到return语句时,return语句完成两项工作,1:返回return语句中的值。2:将控制权从被调函数转移到主调函数。函数的返回值用于初始化调用表达式的结果。

    (4)      函数的实参和形参必须类型一致,或者实参可以通过隐式转换到形参类型

    下面举个例子:

            

    #include<iostream>
    using namespace std;
    int function(int a)  //函数返回类型,名字,参数
    {                     //函数体
    	int c=1;
    	while(a!=1)
    	{
    	   c=c*(a--);
    	}
    	return c;        //返回值
    }
    int main ()
    {
    	cout<<function(5)<<endl;   //调用运算符()执行函数
    
    	return 0;
    }
    运行结果是:

     

      谈到函数中的参数,他们是局部对象,既生命期就是在函数开始执行到函数结束执行期间(生命期:就是对象在程序中存在的时间),形参和定义在函数中的变量都是局部变量,同时,局部变量会隐藏外层作用域中的同名的变量。

    下面举个例子:

         

    //局部静态变量
    #include<iostream>
    using  namespace std;
    
    int Increase()
    {
    	static int a;
    	a++;
    	return a;
    
    }
    //与局部变量的区别在于: 在函数退出时,
    //这个变量始终存在,静态局部变量延长了局部变量的生命周期. 
    //但不能被其它 函数使用, 当再次进入该函数时, 将保存上次的结果。
    //其它的特点与局部变量一样。 
    
    
    int main()
    {
    	for(int i=0;i<5;i++)
    		cout<<"After the function,the result is "<<Increase()<<endl;;
    	     //函数调用结束,该变量仍然存在,没有被销毁,继续累加,但是由于是局部的,只能在函数内被访问。
      return 0;
    }

     



    二:参数传递

    (1)      传值调用,实参通过拷贝给形参,形参和实参是两个相互独立的对象,两者之间互相不影响。

    (2)      传引用调用(主推使用,好处多多):形参是引用类型,即当函数被调用时,形参就是实参的另一个名字,函数中对形参的操纵就是对实参本身的操作(够通俗吧)大笑大笑

    (3)      指针形参,当执行指针拷贝时,以指针参数传递,指针形参:此时将复制实参的指针:形参的改变不会引起实参的改变,但是形参指向的内容可以发生变化。

    文字太乏味,举个例子大家就知道了。

             

    //三种参数传递传递
    #include<iostream>
    using namespace std;
    int Increase1(int a)   //<span style="color:#ff0000;">拷贝的值传递</span>
    {
       a++;
       return a;
    }
    int Increase2( int &a)  //<span style="color:#ff0000;">引用参数传递</span>
    {
      a++;
      return a;
    }
    int Increase3(  int *p)  //<span style="color:#ff0000;">指针参数传递</span>
    {
           (*p)++;
    	   return (*p);
    }
    
    int main()
    {
      int c=5;
      
      Increase1(c);
      cout<<"After the Increase1,the result is "<<c<<endl;
      //以拷贝的方式进行调用,c的值不会变,
       
      Increase2(c);
      cout<<"After the Increase2,the result is "<<c<<endl;
      //以引用的形式进行调用,c的值发生改变。
    
       Increase3(&c);
       cout<<"After the Increase3,the result is "<<c<<endl;  
        //以指针参数传递,指针形参:此时将复制实参的指针:形参的改变不会引起实参的改变,但是形参指向的内容可以发生变化。
       return 0;
    }
    
    运行截图是:

      

       我们建议使用,引用类型的形参代替指针(指针还是用在函数外边好).

    为什么使用引用参数呢?

            我们应该避开那些拷贝传递,拷贝传递费时费力,占资源,使用引用,我们就是直接在对象上操作,不需要拷贝,指针参数也是一样。无论任何是时候,我们都尽量不适用“传值调用”。

           使用引用类型的形参还有一个好处就是,我们要从一个函数中得到多个值,而不是单单一个。举个例子,有一字符串,里面有很多单词,要求,计算出第一个第一个空格(也就是第一个单词后的空格),和所有空格数量,此时要计算出两个值,则我们可以如下:

       

    #include<iostream>
    using namespace std;
    #include <string>
    int find_char(<span style="color:#ff0000;">const string s,int &a</span>)
    {
      cout<<"the string is "<<s<<endl;
      decltype(s.size()) i=0;  //i 的类型个s.size 一样
       i=s.find(' ',0);     //从索引0开始找第一个为空格的,返回索引,失败返回-1
       for(auto b=s.begin();b!=s.end();b++) //使用C++迭代器查找string中总的空格数
       {
           if(*b==' ')
    		 <span style="color:#ff0000;">a++;  //这个引用参数虽然没有输出,但是我们仍然可以得到它,这就是引用的好处</span>
       }
         return i;
    }
    int main()
    {
       string s="Zheng zhengzhou university software institute";
       int k=0;
       cout<<"the blank characters of first index is "<<find_char(s,k)<<endl;
       cout<<"the sum of black characters have "<<k<<endl;  //引用形参,形参改变,实参也跟着改变。
       return 0;  //<span style="color:#ff0000;">实现了一个返回值,却可以得到两个有用的参数</span>
    
    }

     

     

    三:初始化时忽略形参的const特性

      我们使用实参初始化形参时,可以忽略形参的顶层const,通俗一点来说,当形参是const类型,实参是否是const 类型都一样。反之也成立(当实参是常量类型,形参是否是常量类型都一样),只是当形参是常量类型,函数中不允许改编实参。

    例子如下:

       

    //实参初始化形参时,可以忽略形参是否是const类型
    #include<iostream>
    using namespace std;
    
    int add1(const int &a)  
    {
       cout<<a<<endl;
       return 1;
    }
    
    
    int add2(int a,int b)
    {
      cout<<"After the add2,the result is "<<a+b<<endl;
      return 1;
    }
    int main()
    {
    	const int a=9;
    	int b=10;
      add1(a);  //形参是常量,实参是非常量,只要在程序中不改变形参的值即可:
      add1(b);   //使用const实参初始化const形参肯定是没有问题的。
    
      const int c=11;
      const int d=12;
      add2(c,d);  //形参是非常量,实参是常量。
    
      return 0;
    }

      上面的例子告诉我们,尽量使用常量的引用,当在函数中不改变参数时,我们设置为常量。把函数不会改变的形参定义成普通的引用是一种常见的错误,这么做带给函数的调用者一种误导,既函数可以修改它的实参值,使用引用而非常量引用也会极大地限制所能接受的实参类型,例如,我们不能把const 对象,传给普通的引用形参。



    四:形参是数组

      当形参是数组时候,若形参是:a[10],a,a[],这三种形式都一样,原理是:数组会被转换成指针,我们外函数传递数组,其实就是为数组传递数组的首元素的指针。

    例如一下程序:

       

    #include<iostream>   //显式的传入一个数组大小的参数
    using namespace std;
    int print(const char *a,int b)  //数组作为形参的,传递的其实是手首元素指针,其中参数1也可以写成:a[],a[10]
    {
    	for(int i=0;i<b;i++)
    		cout<<a[i]<<endl;
    	return 0;
    }
    
    int main()
    {
    	char a[]="helloworld";
    	//重载函数,编译器根据参数的类型个数判断调用哪个
    	print(a,10); //其实有11个元素,最后一个元素为空
    
    return 0;
    }

     

     

    五:函数的返回类型

    (1)      存在返回值,返回值类型与函数返回类型一致,或者可以隐式转换,返回值通过return 返回到主调函数中。其中,一个返回引用的的函数可以充当左值,其原理和变量可以充当左值是一样的。

    (2)      没有返回值,既renturn ;即可,也可以没有这句话,函数会自动隐式添加这句话。

    举个例子

      

    <span style="font-size:18px;">//返回类型是引用可以当左值
    #include<iostream>
    using namespace std;
    int& function(int &a)
    {
       cout<<"Before the change,the a is"<<a<<endl;
       return a;
    }
    int main()
    {
      int a=4;
      function(a)=50;
      cout<<"after the change,the a is"<<a<<endl;
      return 0;
    }</span>


        第一遍看C++primer,以后还得多看,多想,多练。暂且到这吧奋斗奋斗


  • 相关阅读:
    CCCC L3-015. 球队“食物链”(dfs+剪枝)
    【USACO2.1】解题报告
    【USACO2.1】解题报告
    序列【模拟】
    序列【模拟】
    【JZOJ5184】Gift【DP】【01背包】
    【JZOJ5184】Gift【DP】【01背包】
    【JZOJ5177】TRAVEL【并查集】
    【JZOJ5177】TRAVEL【并查集】
    【JZOJ5178】So many prefix?【KMP】【DP】
  • 原文地址:https://www.cnblogs.com/zhangruilin/p/5769844.html
Copyright © 2020-2023  润新知