精华内容
下载资源
问答
  • 函数参数三种传递方式的区别

    万次阅读 2017-01-07 13:47:00
    问题提出:1、当个类的对象作为实参数传递时,使用值传递和引用传递有什么区别? 比如: DateType ExampleFun(CString &strFileName,…)与 DateType ExampleFun(CString strFileName,…)解答之前,我们先来看2...

    函数参数三种传递方式的区别

    问题提出:

    1、当一个类的对象作为实参数传递时,使用值传递和引用传递有什么区别?
    比如: DateType ExampleFun(CString &strFileName,…)与
    DateType ExampleFun(CString strFileName,…)

    解答之前,我们先来看2个基本的概念:形参和实参。

    ->通俗的讲:形参是形式上的参数,实参是实际的参数;
    ->详细的讲:形参只是对实参的一种抽象类型描述,只是声明一个函数(方法)能接受什么类型的实参,而不确定接受的实参具体内容是多少;

    实参就是传递给函数(方法)对应形参的具体内容(值),形参的初始指(内容)由实参决定.形参在函数(方法)结束返回后就被释放了.

    现在进入主题:参数传递方式分:传值和传址;
    1.传值方式,只是将实参的值的拷贝传递给函数(方法),在方法内对形参进行操作,其对象是实参的拷贝,对实参不能造成影响.在方法结束返回后,形参被释放丢弃,实参的内容并不会改变;

    2.传址方式,将实参的地址传递给函数(方法),在方法内对形参进行操作即等于对实参进行相同的操作,在方法结束返回后,形参同样被释放,实参的内容将会是对形参进行操作的结果.

    而传址方式,又可以细分为:引用传递(pass-by-reference) , 指针传递(pass-by-pointer)

    引用其实就是对象的别名,传对象的引用,用于把一个对象的地址作为参数传过去,而不是对象本身。

    这是我们就明白了前面问题的答案:传递引用,避免了一次实参到形参的拷贝,提高了效率。

    使用引用参数的原因:
    1. 程序员能够修改调用函数中的数据对象

    1. 通过传递引用而不是整个数据对象,可以提高程序的运行速度。

      当数据对象较大时(如结构和类对象),第二个原因最重要,这些也是使用指针参数的原因。这是有道理的,因为引用参数实际上是基于指针的代码的另一个接口。

    那么什么时候使用引用、什么时候使用指针?什么时候又应该按值传递呢?下面是一些指导原则:

    对于使用传递值而不做修改的函数:

    1. 如果数据对象较小,如内置数据类型或者小型结构,则按值传递。

    2. 如果数据对象是数组,则使用指针,因为这是唯一的选择,并将指针声明为指向const的指针。

    3. 如果数据对象是较大的结构,则使用const指针或const引用,以提高运行效率。这样可以节省复制结构所需的时间和空间。

    4. 如果数据对象是类对象,则使用const引用。类设计的语义常常要求使用引用,这是C++增加引用特性的主要原因。因此,传递类对象参数的标准方式是按引用传递。

    对于修改调用函数中数据的函数:

    1. 如果数据对象是内置数据类型,则是用指针。如果看到诸如fixit(&x)这样的代码(其中x是int型),则很明显,该函数将修改x。

    2. 如果数据对象是数组,则只能使用指针。

    3. 如果数据对象是结构,则使用引用或指针。

    4. 如果数据对象是类对象,则使用引用。

    当然,这只是一些指导原则,很可能有充分的理由做出其他的选择。如:对于基本类型,cin使用引用。因此可以使用cin>>n, 而不是cin>>&n 。

    另外找了其他的资料:

    1.

    什么是“引用”?申明和使用“引用”要注意哪些问题?

    引用就是某个目标变量的“别名”(alias),对应用的操作与对变量直接操作效果完全相同。

    申明一个引用的时候,切记要对其进行初始化。引用声明完毕后,相当于目标变量名有两个名称,即该目标原名称和引用名,不能再把该引用名作为其他变量名的别名。声明一个引用,不是新定义了一个变量,它只表示该引用名是目标变量名的一个别名,它本身不是一种数据类型,因此引用本身不占存储单元,系统也不给引用分配存储单元。不能建立数组的引用。

    会调用拷贝构造函数和析构函数

    A a(){…;return *this;}
    A& a(){…;return *this;}
    不会调用拷贝构造函数和析构函数
    应该都能够作为左值

    当返回一个变量时,会产生拷贝。当返回一个引用时,不会发生拷贝,你可以将引用看作是一个变量的别名,就是其他的名字,引用和被引用的变量其实是一个东西,只是有了两个名字而已。

    问题的关键是,当你想要返回一个引用而不是一个拷贝时,你要确保这个引用的有效性,比如:
    int & fun() { int a; a=10; return a; }
    这样是不行的,因为a会在fun退出时被销毁,这时返回的a的引用是无效的。
    这种情况下,如果fun的返回类型不是int & 而是int就没有问题了。

    因此,要返回一个引用时,“临时变量”不能是“临时”的,至少得等函数外部使用完毕这个引用之后,才能销毁它。

    2.返回引用的好处:

    1)传递引用给函数与传递指针的效果是一样的。这时,被调函数的形参就成为原来主调函数中的实参变量或对象的一个别名来使用,所以在被调函数中对形参变量的操作就是对其相应的目标对象(在主调函数中)的操作。

    (2)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量的副本;如果传递的是对象,还将调用拷贝构造函数。因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好。

    (3)使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用”*指针变量名”的形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调函数的调用点处,必须用变量的地址作为实参。而引用更容易使用,更清晰。

    3 在什么时候需要使用“常引用”?

    如果既要利用引用提高程序的效率,又要保护传递给函数的数据不在函数中被改变,就应使用常引用。常引用声明方式:const 类型标识符 &引用名=目标变量名;

    例1

    int a ;

    const int &ra=a;

    ra=1; //错误

    a=1; //正确

    例2

    string foo( );

    void bar(string & s);

    那么下面的表达式将是非法的:

    bar(foo( ));

    bar(“hello world”);

    原因在于foo( )和”hello world”串都会产生一个临时对象,而在C++中,这些临时对象都是const类型的。因此上面的表达式就是试图将一个const类型的对象转换为非const类型,这是非法的。

    引用型参数应该在能被定义为const的情况下,尽量定义为const 。

    1. 将“引用”作为函数返回值类型的格式、好处和需要遵守的规则?

    格式:类型标识符 &函数名(形参列表及类型说明){ //函数体 }

    好处:在内存中不产生被返回值的副本;(注意:正是因为这点原因,所以返回一个局部变量的引用是不可取的。因为随着该局部变量生存期的结束,相应的引用也会失效,产生runtime error!

    注意事项:

    (1)不能返回局部变量的引用。这条可以参照Effective C++[1]的Item 31。主要原因是局部变量会在函数返回后被销毁,因此被返回的引用就成为了”无所指”的引用,程序会进入未知状态。

    (2)不能返回函数内部new分配的内存的引用。这条可以参照Effective C++[1]的Item 31。虽然不存在局部变量的被动销毁问题,可对于这种情况(返回函数内部new分配内存的引用),又面临其它尴尬局面。例如,被函数返回的引用只是作为一个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就无法释放,造成memory leak。

    (3)可以返回类成员的引用,但最好是const。这条原则可以参照Effective C++[1]的Item 30。主要原因是当对象的属性是与某种业务规则(business rule)相关联的时候,其赋值常常与某些其它属性或者对象的状态有关,因此有必要将赋值操作封装在一个业务规则当中。如果其它对象可以获得该属性的非常量引用(或指针),那么对该属性的单纯赋值就会破坏业务规则的完整性。

    (4)流操作符重载返回值申明为“引用”的作用:

    流操作符<<和>>,这两个操作符常常希望被连续使用,例如:cout << “hello” << endl; 因此这两个操作符的返回值应该是一个仍然支持这两个操作符的流引用。可选的其它方案包括:返回一个流对象和返回一个流对象指针。但是对于返回一个流对象,程序必须重新(拷贝)构造一个新的流对象,也就是说,连续的两个<<操作符实际上是针对不同对象的!这无法让人接受。对于返回一个流指针则不能连续使用<<操作符。因此,返回一个流对象引用是惟一选择。这个唯一选择很关键,它说明了引用的重要性以及无可替代性,也许这就是C++语言中引入引用这个概念的原因吧。赋值操作符=。这个操作符象流操作符一样,是可以连续使用的,例如:x = j = 10;或者(x=10)=100;赋值操作符的返回值必须是一个左值,以便可以被继续赋值。因此引用成了这个操作符的惟一返回值选择。

    例3

    #include

    展开全文
  • javascript函数三种定义方式及区别

    千次阅读 2017-03-14 22:46:47
    js有三种定义函数方式: 1.function 语句形式 2.函数直接量形式 3.通过Function构造函数形式定义函数 <script type="text/javascript"> //3种函数定义方式,前两常用 /** * 1,...

    js有三种定义函数的方式:

    1.function 语句形式

    2.函数直接量形式

    3.通过Function构造函数形式定义函数

     

      <script type="text/javascript">
    		    //3种函数定义方式,前两种常用
    
    		    /**
    		     * 1,function 语句式
    		     * 形式:句子
    		     * 名称:有名
    		     * 性质:静态
    		     * 解析时机:优先解析
    		     * 作用域:具有函数的作用域(正常的作用域)
    		     */
    		    function test1() {
    		        alert("我是test1");
    		    }
    		    //test1();
    
    
    		    /**
    		     * 2,函数直接量 ECMAScript 推荐的方式
    		     * 形式:表达式
    		     * 名称:匿名
    		     * 性质:静态
    		     * 解析时机:顺序解析
    		     * 作用域:具有函数的作用域(正常的作用域)
    		     */
    		    var test2 = function() {
    		        alert("我是test2");
    		    };
    		    //test2();
    
    		    /**
    		     * 3,function 构造函数式,a,b是形参,函数执行体直接写在后边,以分号结束
    		     * 形式:表达式
    		     * 名称:匿名
    		     * 性质:动态
    		     * 解析时机:顺序解析
    		     * 作用域:顶级函数(顶级作用域)
    		     */
    		    var test3 = new Function("a", "b", "return a+b;");
    		    //alert(test3(10,20));
        </script>


    比较三种形式的区别:

     

    1.效率方面:通过下面的方法比较

     

        <script>
        	//三种方式效率的对比
                var d1 = new Date();
                var t1 =d1.getTime();
                for(var i=0;i<100000;i++){
                    function test1(){ ;}; //function语句式
                    //var test2 = new Function(); //构造函数式
                }
                
                var d2 = new Date();
                var t2 = d2.getTime();
                alert(t2-t1);
                //function语句式 12秒左右
                // 构造函数式 77秒左右
        </script>	//三种方式效率的对比
                var d1 = new Date();
                var t1 =d1.getTime();
                for(var i=0;i<100000;i++){
                    function test1(){ ;}; //function语句式
                    //var test2 = new Function(); //构造函数式
                }
                
                var d2 = new Date();
                var t2 = d2.getTime();
                alert(t2-t1);
                //function语句式 12秒左右
                // 构造函数式 77秒左右
        </script>

    可以看到function语句式比构造函数式效率要高,函数直接量和function语句式效率差不多。

     

    原因:这就上边说的性质--静态和动态的区别,函数直接量和function语句式被javascript解释一次,放在了内存,以后用到的话直接调用,占用内存,所以说是“静态”的。而构

    造函数式是每一次调用都动态新建一个,用完之后就销毁了,不占用内存,所以说是“动态”的。所以,有些程序只希望调用一次,就可以用动态的构造函数式。

    2.解析、执行顺序:

    下面是一种经典的比较方法:

     

     <script>
        	/**
             * ************************解析顺序*******************************************,
             * 对于function语句式的函数,javascript解析器会优先的解释
             * javascript解析器会先看所有的全局变量,放到内存,test04()、test05会被当做全局变量
             * test4()能正常执行,但是test5只有被定义,并没被赋值 所以会有undefined
             */
            //test4();
            // function test4(){
                // alert("test4");
            // }
            
            //test5(); 执行不了,缺少对象
            /**
             * undefined,表示变量声明了,没有被赋值,
             * 执行到此步时,还没有把function赋给test5,相当于先声明后赋值的概念
             */
            //alert(test5);
            var test5 = function(){
                alert("test5");
            };
            
            
            //********************执行顺序经典例子**************
            /**
             * js解析器会先找所有的function当做全局变量放内存,就找到了1,4,静态的,4把1覆盖,
             * 执行到函数1,所以打印4
             * 执行到函数2,是动态构建的覆盖4,所以打印2,之后销毁
             * 执行到函数3,覆盖函数4,打印3
             * 执行到函数4,其实调用的是函数3,打印3
             * 执行到函数5,动态创建一个覆盖3,打印5,后销毁
             * 执行到函数6,覆盖函数3,打印6
             */
            //alert结果:4 2 3 3 5 6
            function f(){ return 1;}             //函数1
            alert(f());        //返回值为4,说明第1个函数被第4个函数覆盖,
            
            var f = new Function("return 2;");    //函数2
            alert(f());        //返回值为2,说明第4个函数被第2个函数覆盖
            
            var f =  function(){ return 3;};    //函数3
            alert(f());        //返回值为3,说明第4个函数被第3个函数覆盖
            
            function f(){ return 4;}            //函数4
            alert(f());        //返回值为3,说明第4个函数被第3个函数覆盖
            
            var f = new Function("return 5;");    //函数5
            alert(f());        //返回值为5,说明第3个函数被第5个函数覆盖
            
            var f =  function(){ return 6;};    //函数6
            alert(f());        //返回值为6,说明第3个函数被第6个函数覆盖
        </script>


    3.函数作用域

     

     

     <script>
     		/**
             * ******************函数作用域的概念*************************
             */
            //var test = new Function("return k;");
            var k = 1;
            function t1(){
                var k = 2;    //局部变量
                //function test(){ return k; }        //function语句式,k=2
                //var test =     function(){ return k;};   //函数直接量,k=2 ,两者都是函数的作用域
                var test = new Function("return k;");    //构造函数,顶级的作用域,相当于在全局new一个函数,只能找到全局的k=1
                alert(test());
            }
            t1();
     </script>

    总结

     

     1,function语句式、函数直接量 就会被解释一次,是静态的,有函数的作用域,Function构造函数式每次执行都动态new一次,说明有顶级作用域。

     2,解析机制,function语句式 相当于全局变量,会被优先解析,其他2种执行到哪解释到哪,顺序执行。

     

    展开全文
  • C语言中函数参数传递的三种方式

    万次阅读 多人点赞 2017-07-22 21:09:40
    C语言中函数参数传递的三种方式(1)传值,就是把你的变量的值传递给函数的形式参数,实际就是用变量的值来新生成一个形式参数,因而在函数里对形参的改变不会影响到函数外的变量的值。(2)传址,就是传变量的地址...

    C语言中函数参数传递的三种方式

    (1)传值,就是把你的变量的值传递给函数的形式参数,实际就是用变量的值来新生成一个形式参数,因而在函数里对形参的改变不会影响到函数外的变量的值。
    (2)传址,就是传变量的地址赋给函数里形式参数的指针,使指针指向真实的变量的地址,因为对指针所指地址的内容的改变能反映到函数外,也就是能改变函数外的变量的值。
    (3)传引用,实际是通过指针来实现的,能达到使用的效果如传址,可是使用方式如传值。
    说几点建议:如果传值的话,会生成新的对象,花费时间和空间,而在退出函数的时候,又会销毁该对象,花费时间和空间。
    因而如果int,char等固有类型,而是你自己定义的类或结构等,都建议传指针或引用,因为他们不会创建新的对象。


    例1:下面这段代码的输出结果为:
    #include<stdio.h>
    void change(int*a, int&b, int c)
    {
          c=*a;
          b=30;
          *a=20;
    }
    int main ( )
    {
          int a=10, b=20, c=30;
          change(&a,b,c);
          printf(“%d,%d,%d,”,a,b,c);
          return 0;
     }
    结果:20  30  30


    解析:
    该题考察函数传参问题。
    1,指针传参 -> 将变量的地址直接传入函数,函数中可以对其值进行修改。
    2,引用传参 -> 将变量的引用传入函数,效果和指针相同,同样函数中可以对其值进行修改。
    3,值传参   -> 在传参过程中,首先将c的值复制给函数c变量,然后在函数中修改的即是函数的c变量,然后函数返回时,系统自动释放变量c。而对main函数的c没有影响。


    例2:
    #include<stdio.h>  
    void myswap(int x, int y)  
    {  
        int t;  
        t=x;  
        x=y;  
        y=t;  
    }  
    int main()  
    {  
        int a, b;  
        printf("请输入待交换的两个整数:");  
        scanf("%d %d", &a, &b);  
        myswap(a,b);  //作为对比,直接交换两个整数,显然不行  
        printf("调用交换函数后的结果是:%d 和 %d\n", a, b);  
        return 0;  
    }  
     
     
    #include<stdio.h>  
    void myswap(int *p1, int *p2)  
    {  
        int  t;  
        t=*p1;  
        *p1=*p2;  
        *p2=t;  
    }  
    int main()  
    {  
        int a, b;  
        printf("请输入待交换的两个整数:");  
        scanf("%d %d", &a, &b);  
        myswap(&a,&b);  //交换两个整数的地址  
        printf("调用交换函数后的结果是:%d 和 %d\n", a, b);  
        return 0;  
    }  
     
    #include<stdio.h>  
    void myswap(int &x, int &y)  
    {  
        int t;  
        t=x;  
        x=y;  
        y=t;  
    }  
      
    int main()  
    {  
        int a, b;  
        printf("请输入待交换的两个整数:");  
        scanf("%d %d", &a, &b);  
        myswap(a,b);  //直接以变量a和b作为实参交换  
        printf("调用交换函数后的结果是:%d 和 %d\n", a, b);  
        return 0;  
    }  
    第一个的运行结果:输入2 3,输出2 3 
    第二个的运行结果:输入2 3,输出3 2
    第三个的运行结果:输入2 3,输出3 2

    解析:
    在第一个程序中,传值不成功的原因是指在形参上改变了数值,没有在实参上改变数值。
    在第二个程序中,传地址成功的原因利用指针改变了原来的地址,所以实参就交换了。

    在第三个程序中,引用是直接改变两个实参变量a,b的值,所以就交换了。

    下文会通过例子详细说明关于值传递,指针传递,引用传递 

      1)值传递:

        形参是实参的拷贝,改变形参的值并不会影响外部实参的值。从被调用函数的角度来说,值传递是单向的(实参->形参),参数的值只能传入,

    不能传出。当函数内部需要修改参数,并且不希望这个改变影响调用者时,采用值传递。

      2)指针传递:

        形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作

      3)引用传递:

        形参相当于是实参的“别名”,对形参的操作其实就是对实参的操作,在引用传递过程中,被调函数的形式参数虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。

        下面的代码对此作出了细致解释(从实参,形参在内存中存放地址的角度 说明了问题的本质,容易理解  )

     1 #include<iostream>
     2 using namespace std;
     3 //值传递
     4  void change1(int n){
     5     cout<<"值传递--函数操作地址"<<&n<<endl;         //显示的是拷贝的地址而不是源地址 
     6     n++;
     7 }
     8 
     9 //引用传递
    10 void change2(int & n){
    11     cout<<"引用传递--函数操作地址"<<&n<<endl; 
    12     n++;
    13 }
    14  //指针传递
    15 void change3(int *n){
    16      cout<<"指针传递--函数操作地址 "<<n<<endl; 
    17     *n=*n+1;
    18  } 
    19 int     main(){
    20     int n=10;
    21     cout<<"实参的地址"<<&n<<endl;
    22     change1(n);
    23     cout<<"after change1() n="<<n<<endl;
    24     change2(n);
    25     cout<<"after change2() n="<<n<<endl;
    26     change3(&n);
    27     cout<<"after change3() n="<<n<<endl;
    28     return true;
    29 }

    运行结果如下,(不同的机器可能会有所差别)

    可以看出,实参的地址为0x22ff44

        采用值传递的时候,函数操作的地址是0x22ff20并不是实参本身,所以对它进行操作并不能改变实参的值

    • 再看引用传递,操作地址就是实参地址 ,只是相当于实参的一个别名,对它的操作就是对实参的操作
    • 接下来是指针传递,也可发现操作地址是实参地址

        那么,引用传递和指针传递有什么区别吗?

      引用的规则: 
    引用被创建的同时必须被初始化(指针则可以在任何时候被初始化)。 

    • 不能有NULL引用,引用必须与合法的存储单元关联(指针则可以是NULL)。 
    • 一旦引用被初始化,就不能改变引用的关系(指针则可以随时改变所指的对象)。 

      指针传递的实质:

        指针传递参数本质上是值传递的方式,它所传递的是一个地址值。值传递过程中,被调函数的形式参数作为被调函数的局部变量处理,即在栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本。值传递的特点是被调函数对形式参数的

        任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值。(这里是在说实参指针本身的地址值不会变)如果理解不了大可跳过这段

      指针传递和引用传递一般适用于:

        函数内部修改参数并且希望改动影响调用者。对比指针/引用传递可以将改变由形参“传给”实参(实际上就是直接在实参的内存上修改,不像值传递将实参的值拷贝到另外的内存地址中才修改)。

        另外一种用法是:当一个函数实际需要返回多个值,而只能显式返回一个值时,可以将另外需要返回的变量以指针/引用传递给函数,这样在函数内部修改并且返回后,调用者可以拿到被修改过后的变量,也相当于一个隐式的返回值传递吧。

        以下是我觉得关于指针和引用写得很不错的文章,大家可参照看一下,原文出处地址:http://xinklabi.iteye.com/blog/653643 

        从概念上讲。指针从本质上讲就是存放变量地址的一个变量,在逻辑上是独立的,它可以被改变,包括其所指向的地址的改变和其指向的地址中所存放的数据的改变。

        而引用是一个别名,它在逻辑上不是独立的,它的存在具有依附性,所以引用必须在一开始就被初始化,而且其引用的对象在其整个生命周期中是不能被改变的(自始至终只能依附于同一个变量)。

        在C++中,指针和引用经常用于函数的参数传递,然而,指针传递参数和引用传递参数是有本质上的不同的:

        指针传递参数本质上是值传递的方式,它所传递的是一个地址值。值传递过程中,被调函数的形式参数作为被调函数的局部变量处理,即在栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本。值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值。(这里是在说实参指针本身的地址值不会变)

    而在引用传递过程中,被调函数的形式参数虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。

        引用传递和指针传递是不同的,虽然它们都是在被调函数栈空间上的一个局部变量,但是任何对于引用参数的处理都会通过一个间接寻址的方式操作到主调函数中的相关变量。而对于指针传递的参数,如果改变被调函数中的指针地址,它将影响不到主调函数的相关变量。如果想通过指针参数传递来改变主调函数中的相关变量,那就得使用指向指针的指针,或者指针引用。

    为了进一步加深大家对指针和引用的区别,下面我从编译的角度来阐述它们之间的区别:

    程序在编译时分别将指针和引用添加到符号表上,符号表上记录的是变量名及变量所对应地址。指针变量在符号表上对应的地址值为指针变量的地址值,而引用在符号表上对应的地址值为引用对象的地址值。符号表生成后就不会再改,因此指针可以改变其指向的对象(指针变量中的值可以改),而引用对象则不能修改。

    最后,总结一下指针和引用的相同点和不同点:

      1)相同点:

    • 都是地址的概念;

    指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名。

      2)不同点:

    • 指针是一个实体,而引用仅是个别名;
    • 引用只能在定义时被初始化一次,之后不可变;指针可变;引用“从一而终”,指针可以“见异思迁”;
    • 引用没有const,指针有const,const的指针不可变;(具体指没有int& const a这种形式,而const int& a是有     的,  前者指引用本身即别名不可以改变,这是当然的,所以不需要这种形式,后者指引用所指的值不可以改变)
    • 引用不能为空,指针可以为空;
    • “sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身的大小;
    • 指针和引用的自增(++)运算意义不一样;
    • 引用是类型安全的,而指针不是 (引用比指针多了类型检查)

    复制代码

    一、引用的概念
    
    引用引入了对象的一个同义词。定义引用的表示方法与定义指针相似,只是用&代替了*。
    例如: Point pt1(10,10);
    Point &pt2=pt1; 定义了pt2为pt1的引用。通过这样的定义,pt1和pt2表示同一对象。
    需要特别强调的是引用并不产生对象的副本,仅仅是对象的同义词。因此,当下面的语句执行后:
    pt1.offset(22);
    pt1和pt2都具有(1212)的值。
    引用必须在定义时马上被初始化,因为它必须是某个东西的同义词。你不能先定义一个引用后才
    初始化它。例如下面语句是非法的:
    Point &pt3;
    pt3=pt1;
    那么既然引用只是某个东西的同义词,它有什么用途呢?
    下面讨论引用的两个主要用途:作为函数参数以及从函数中返回左值。 
    
    二、引用参数
    
    1、传递可变参数
    传统的c中,函数在调用时参数是通过值来传递的,这就是说函数的参数不具备返回值的能力。
    所以在传统的c中,如果需要函数的参数具有返回值的能力,往往是通过指针来实现的。比如,实现
    两整数变量值交换的c程序如下:
    一、引用的概念
    
    引用引入了对象的一个同义词。定义引用的表示方法与定义指针相似,只是用&代替了*。
    例如: Point pt1(10,10);
    Point &pt2=pt1; 定义了pt2为pt1的引用。通过这样的定义,pt1和pt2表示同一对象。
    需要特别强调的是引用并不产生对象的副本,仅仅是对象的同义词。因此,当下面的语句执行后:
    pt1.offset(2,2);
    pt1和pt2都具有(12,12)的值。
    引用必须在定义时马上被初始化,因为它必须是某个东西的同义词。你不能先定义一个引用后才
    初始化它。例如下面语句是非法的:
    Point &pt3;
    pt3=pt1;
    那么既然引用只是某个东西的同义词,它有什么用途呢?
    下面讨论引用的两个主要用途:作为函数参数以及从函数中返回左值。 
    
    二、引用参数
    
    1、传递可变参数
    传统的c中,函数在调用时参数是通过值来传递的,这就是说函数的参数不具备返回值的能力。
    所以在传统的c中,如果需要函数的参数具有返回值的能力,往往是通过指针来实现的。比如,实现
    两整数变量值交换的c程序如下:
    void swapint(int *a,int *b)
    {
    int temp;
    temp=*a;
    a=*b;
    *b=temp;
    }
    
    使用引用机制后,以上程序的c++版本为:
    void swapint(int &a,int &b)
    {
    int temp;
    temp=a;
    a=b;
    b=temp;
    }
    调用该函数的c++方法为:swapint(x,y); c++自动把x,y的地址作为参数传递给swapint函数。
    
    2、给函数传递大型对象
    当大型对象被传递给函数时,使用引用参数可使参数传递效率得到提高,因为引用并不产生对象的
    副本,也就是参数传递时,对象无须复制。下面的例子定义了一个有限整数集合的类: 
    const maxCard=100; 
    Class Set 
    {
    int elems[maxCard]; // 集和中的元素,maxCard 表示集合中元素个数的最大值。 
    int card; // 集合中元素的个数。 
    public:
    Set () {card=0;} //构造函数
    friend Set operator * (Set ,Set ) ; //重载运算符号*,用于计算集合的交集 用对象作为传值参数
    // friend Set operator * (Set & ,Set & ) 重载运算符号*,用于计算集合的交集 用对象的引用作为传值参数 
    ...
    }
    先考虑集合交集的实现
    Set operator *( Set Set1,Set Set2)
    {
    Set res;
    for(int i=0;i<Set1.card;++i)
    for(int j=0;j>Set2.card;++j)
    if(Set1.elems[i]==Set2.elems[j])
    {
    res.elems[res.card++]=Set1.elems[i];
    break;
    }
    return res;
    }
    由于重载运算符不能对指针单独操作,我们必须把运算数声明为 Set 类型而不是 Set * 。
    每次使用*做交集运算时,整个集合都被复制,这样效率很低。我们可以用引用来避免这种情况。
    Set operator *( Set &Set1,Set &Set2)
    { Set res;
    for(int i=0;i<Set1.card;++i)
    for(int j=0;j>Set2.card;++j)
    if(Set1.elems[i]==Set2.elems[j])
    {
    res.elems[res.card++]=Set1.elems[i];
    break;
    }
    return res;
    }
    
    三、引用返回值
    
    如果一个函数返回了引用,那么该函数的调用也可以被赋值。这里有一函数,它拥有两个引用参数并返回一个双精度数的引用:
    double &max(double &d1,double &d2)
    {
    return d1>d2?d1:d2;
    }
    由于max()函数返回一个对双精度数的引用,那么我们就可以用max() 来对其中较大的双精度数加1:
    max(x,y)+=1.0;

     

    展开全文
  • 欧拉函数三种基本写法

    千次阅读 2018-08-06 18:27:03
     欧拉函数的性质:它在整数n上的值等于对n进行素因子分解后,所有的素数幂上的欧拉函数之积。  欧拉函数的值 通式:φ(x)=x(1-1/p1)(1-1/p2)(1-1/p3)(1-1/p4)…..(1-1/pn),其中p1, p2……pn为x的所有质因数,x是...

     概念梳理:  

         欧拉函数是少于或等于n的数中与n互质的数的数目。 

         欧拉函数的性质:它在整数n上的值等于对n进行素因子分解后,所有的素数幂上的欧拉函数之积。

         欧拉函数的值  通式:φ(x)=x(1-1/p1)(1-1/p2)(1-1/p3)(1-1/p4)…..(1-1/pn),其中p1, p2……pn为x的所有质因数,x是不为0的整数。φ(1)=1(唯一和1互质的数(小于等     于1)就是1本身)。 (注意:每种质因数只一个。比如12=2*2*3那么φ(12)=12*(1-1/2)*(1-1/3)=4)

        推论:当n为奇数时,有φ(2n)=φ(n)。

        若n是质数p的k次幂,φ(n)=p^k-p^(k-1)=(p-1)p^(k-1),因为除了p的倍数外,其他数都跟n互质。

        设n为正整数,以 φ(n)表示不超过n且与n互素的正整数的个数,称为n的欧拉函数值,这里函数φ:N→N,n→φ(n)称为欧拉函数。

        欧拉函数是积性函数——若m,n互质,φ(mn)=φ(m)φ(n)。

        特殊性质:当n为奇数时,φ(2n)=φ(n), 证明与上述类似。

      算法实现与分析:

       求解欧拉函数的值可用φ(x)=x(1-1/p1)(1-1/p2)(1-1/p3)(1-1/p4)…..(1-1/pn),容易知道要对n进行素因子分解。

        (1)直接实现   题目

    int oula(int n)
    {
        int rea=n;
        for(int i=2; i<=n; i++)
            if(n%i==0)//第一次找到的必为素因子
            {
                rea=rea/i*(i-1);
                do
                    n/=i;//把该素因子全部约掉
                while(n%i==0);
            }
        return rea;
    }

    这个函数的复杂度为O(n),如果n达到1000000000,肯定会超时,由于任何一个合数都至少有一个不大于根号n的素因子,所以只需遍历到根号n即可,这样复杂度降为O(√¯n)

        下面是优化代码:

    int oula(int n)
    {
        int rea=n;
        for(int i=2; i*i<=n; i++)
            if(n%i==0)//第一次找到的必为素因子
            {
                rea=rea/i*(i-1);
                do
                    n/=i;//把该素因子全部约掉
                while(n%i==0);
            }
        if(n>1)
            rea=rea-rea/n;
        return rea;
    }

    (2)素数表实现

        先把50 000以内的素数用筛选法选出来并保存,以方便欧拉函数使用,这样,在不考虑筛选法的时间复杂度,而单纯看欧拉函数,其复杂度为O(x),x为O(√¯n)以内素数的个数。

    bool boo[50000];
    int p[20000];
    void prim()
    {
        memset(boo,0,sizeof(boo));
        boo[0]=boo[1]=1;
        int k=0;
        for(int i=2; i<50000; i++)
        {
            if(!boo[i])
                p[k++]=i;
            for(int j=0; j<k&&i*p[j]<50000; j++)
            {
                boo[i*p[j]=1;
                    if(!(i%p[j]))
                    break;
            }
    }
    }//筛选法打表
    int phi(int n)
    {
        int rea=n;
        for(int i=0; p[i]*p[i]<=n; i++)//对于一些不是素数的可不遍历
            if(n%p[i]==0)
            {
                rea=rea-rea/n;
                do
                    n/=p[i];
                while(n%p[i]==0);
            }
        if(n>1)
            rea=rea-rea/n;
        return rea;
    }

    (3)递推求欧拉函数   题目

         如果频繁的使用欧拉函数值,就需要预先打表,下面介绍递推求欧拉公式的方法。

        可预先之所有数的欧拉函数值都为她本身,有定理可知,如果p是一个正整数且满足φ(p)=p-1;那么p是素数,在遍历过程中如果遇到欧拉函数与自身相等的情况。那么说明该数为素数,把这个数的欧拉函数值改变,同时也把能被素因子整除的数改变。

    for(i=1; i<=maxn; i++)
        p[i]=i;
    for(i=2; i<=maxn; i+=2)
        p[i]/=2;
    for(i=3; i<=maxn; i+=2)
        if(p[i]==i)
        {
            for(j=i; j<=maxn; j+=i)
                p[j]=p[j]/i*(i-1);
        }

     

    展开全文
  • JavaScript中函数三种定义方法

    万次阅读 2017-04-03 11:51:10
    本文整理了JavaScript中函数定义的三种方法。 函数三种定义方法分别是:函数定义语句、函数直接量表达式和Function()构造函数的方法。下面依次介绍这几方法具体怎么实现。 1. 函数定义语句 //求和函数 function ...
  • c++ 构造函数详解

    万次阅读 多人点赞 2019-05-31 17:20:58
    c++构造函数详解。(构造函数的分类、拷贝构造函数
  • python自定义函数在运行时,最初只是存在内存中,只有调用时才会触发运行。def cube_count(a): if is_number(a): return a**3 else: print("非数字不能计算立方值") def is_number(a): if not ...
  • C/C++函数调用的几种方式总结

    千次阅读 2017-07-26 13:54:19
    本篇文章主要是对C/C++函数调用的几种方式进行了详细的总结介绍,需要的朋友可以过来参考下,希望对大家有所帮助 调用函数时,计算机常用栈来存储传递给函数的参数。 栈是一种先进后出的数据结构,栈有个...
  • 1.维插值函数Matlab中有现成的维插值函数interp1,语法为 y=interp1(x0,y0,x,'method')x0,y0是已知的数据向量,其中x应以升序或者降序排列(所有的插值方法要求x0是单调的),x1是插值点的自变量坐标向量;...
  • 1. 最常规的用法: ... //新建个按钮 QPushButton * btn = new QPushButton(this); btn->setText("设置"); //将信号和槽连接 其中btnclicked()为自定义的槽函数 connect(btn, SIGNAL(clicked()), th...
  • 函数可以一次定义,多次调用。 函数的声明 JavaScript 有三种声明函数的方法。 (1)function 命令 function是一个关键字,和var、typeof一样,都是关键字,后面要加空格。 函数名字的命名规定,和变量的...
  • 这个方法中传入了两个参数,一个是函数引用,注意,是函数引用,所以后面不能加(),第二个参数是一个时间,它的意思是,每隔一定时间执行一次传入的函数。 比如,这里写一个显示当前时间的函数: var time=new...
  • Python-定义函数.练习题.求一元二方程解

    万次阅读 多人点赞 2016-04-15 20:02:45
    请定义函数 ’quadratic(a,b,c)‘,接收个参数,返回一元二方程: ax² + bx + c = 0 的两个解。(提示:计算平方根可以调用math.sqrt()函数) 答案: import math def quadratic (a,b,c) : ...
  • swap函数

    万次阅读 多人点赞 2019-02-25 17:23:02
    这是我做过的一道笔试题,开始我觉得答案是5,10,world hello,hello world;当我编译后才发现错了。 最后百度才发现原来是把SWAP函数的形参和实参搞混了。 当交换的是两个int型值时,实参应该取变量的地址:即swap...
  • 详解第范式、第二范式、第范式、BCNF范式

    万次阅读 多人点赞 2019-03-02 16:08:45
    文章目录第范式定义以及分析:问题研究:第二范式必备知识点函数依赖:码:非主属性 :定义分析:解决办法:问题研究:第范式:定义:分析:问题研究:BCNF范式分析问题研究小结: 第范式 定义以及分析: 首先是...
  • Python列表排序 list.sort方法和内置函数sorted

    万次阅读 多人点赞 2019-05-18 15:17:54
    Python列表排序 list.sort方法和内置函数sorted 很多时候我们获取到个列表后,这个列表并不满足我们的需求,我们需要的是个有特殊顺序的列表. 这时候就可以使用list.sort方法和内置函数sorted,本文就是介绍list....
  • C语言求一元二次函数的解

    千次阅读 2016-10-30 13:49:41
    #include #include int main() { float a=0; float b=3;  float c=2; float x1,x2; float m=b*b-4*a*c;... printf("该函数不是一元二次函数\n"); printf("x = %lf\n",x1); } else {
  • 高等数学 · 第函数

    千次阅读 多人点赞 2019-05-16 18:46:28
    高等数学·第函数节 实数 第二节 函数的定义及其表示函数的几特性 第四节 反函数和复合函数 第五节 初等函数 第六节 总结
  • C/C++函数调用的几种方式

    千次阅读 2013-06-10 15:48:30
    我们知道,调用函数时,计算机常用栈来存放函数执行需要的参数,由于栈的空间大小是有限的,在windows下栈是向低地址扩展的数据结构,是块连续的内存区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定...
  • MATLAB函数速查手册

    千次阅读 多人点赞 2018-03-25 09:06:26
    《MATLAB函数速查手册》较全面地介绍了MATLAB的函数,主要包括MATLAB操作基础、矩阵及其基本运算、与数值计算相关的基本函数、符号运算的函数、概率统计函数、绘图与图形处理函数、MATLAB程序设计相关函数、Simulink...
  • fgets函数

    万次阅读 多人点赞 2015-01-12 15:18:20
    在《征服C指针》中很少用到scanf()函数,而是使用fgets函数和sscanf函数的组合,于是仔细看了下fgets函数的用法。  char *fgets(char *s, int size, FILE *stream);  fgets() reads in at most one less than...
  • 常用的激活函数

    千次阅读 2018-08-30 11:13:35
    1. sigmod函数 函数公式和图表如下图   在sigmod函数中我们可以看到,其输出是在[0,1]这个开区间内,我们可以联想到概率,但是严格意义上讲,不要当成概率。sigmod函数曾经是比较流行的,它可以想象成一个神经元...
  • matlab三次样条曲线的绘制(spline和csape函数详解)

    万次阅读 多人点赞 2018-12-05 22:30:29
    对于样条本身,可以利用材料力学的大柔度梁理论建立梁的挠度方程,根据理论,样条可以用分段插值三次函数表示。 由于样条曲线具有连续的二阶导数,所以光滑性好。matlab里有两个函数可以绘制样...
  • 一次调用,两次返回-------fork函数学习总结  以前一直迷惑,什么叫一次调用,两次返回。通过上网搜索,终于知其原由。现将自己的理解记录于此。  准备知识:  内存中的进程包括个部分:可执行文件(即程序...
  • js中for循环中调用函数----三种方法

    千次阅读 2019-09-14 17:22:37
    一种:用this 用this来调用,不然会报错 因为var定义的i的值在每次循环的时候并不会被锁定,而当我们点击的时候(这动作是在循环完成后进行的,此时的i代表的是元素的总个数的值)。 for(var i=0;i<lists....
  • 数模比赛中,常常需要根据已知的函数点进行数据、模型的处理和 分析,而有时候现有的数据是极少的,不足以支撑分析的进行,这时就需要使用一些数学的方法,“模拟产生”一些新的但又比较靠谱的值来满足需求,这就是...
  • * 写函数,输入n,求斐波那契(Fibonacci) 数列的第n项 * @param n Fibonacci数的项数 * @return 第n项的结果 在数学上,费波那契数列是以递归的方法来定义: (n≧2) public static long fibonacci(int...
  • 在很多实际问题中,由于样本特征空间的类条件概率密度的...线性判别函数法是一种较为简单的判别函数,最简单的是线性函数,它的分界面是超平面,采用线性判别函数所产生的错误率或风险虽然可能比贝叶斯分类器来的...
  • 关于将函数的地址作为参数传递给另函数调用

    千次阅读 多人点赞 2015-10-26 22:38:25
    要知道在C语言中,函数内部是可以直接调用其他函数的,既然可以直接调用,为什么还要用这么麻烦的办法去把函数当做参数来传递呢。下面我举个例子。 例如我们设计个estimate() 的函数计算个程序运行的时间,...
  • 高斯径向基函数(RBF)神经网络

    万次阅读 多人点赞 2019-04-03 00:53:52
    高斯径向基函数(RBF)神经网络 牛顿插值法-知乎 ...说径向基网络之前,先聊下径向基函数径向基函数(英语:radial basis function,缩写为RBF)是个取值仅依赖于到原点距离的实值函数,即 ϕ(x...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,493,087
精华内容 597,234
关键字:

一次函数的三种表达方式