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

    千次阅读 2019-03-29 08:46:13
    1. 值传递 #include <stdio.h> void swap(int x, int y); void swap(int x, int y) { int temp; temp = x; x = y; y = temp; } int main( int argc, char *argv[] ) { int a = 5; in...

    1. 值传递

    #include <stdio.h>
    
    void swap(int m, int n);
    void swap(int m, int n)
    {
        int temp;
        temp = m;
        m = n;
        n = temp;
    }
    
    int main( int argc, char *argv[] )
    {
        int a = 10;
        int b = 20;
        swap(a, b); //调用交换函数
        printf("交换结果为 a = %d, b = %d\n",a,b);
        return 0;
    }

    由于值传递是单向传递,传递过程中只是改变了形参的数值,并未改变实参的数值,因此并不会改变a和b原有的值。

    2. 指针传递

    #include <stdio.h>
    
    void swap(int *m, int *n);
    void swap(int *m, int *n)
    {
        int temp;
        temp = *m;
        *m = *n;
        *n = temp;
    }
    
    int main( int argc, char *argv[] )
    {
        int a = 10;
        int b = 20;
        swap(&a, &b); //调用交换函数
        printf("交换结果为 a = %d, b = %d\n",a,b);
        return 0;
    }

    指针传递过程中,将a和b的地址分别传递给了x和y,在函数体内部改变了a、b所在地址的值,即交换了a、b的数值。

    3. 引用传递

    #include <stdio.h>
    
    void swap(int &x, int &y);
    void swap(int &x, int &y)
    {
        int temp;
        temp = x;
        x = y;
        y = temp;
    }
    
    int main( int argc, char *argv[] )
    {
        int a = 5;
        int b = 10;
        swap(a, b); //调用交换函数
        printf("交换结果为 a = %d, b = %d\n",a,b);
        return 0;
    }

    引用传递中,在调用swap(a, b);时函数会用a、b分别代替x、y,即x、y分别引用了a、b变量,这样函数体中实际参与运算的其实就是实参a、b本身,因此也能达到交换数值的目的。

    注:严格来说,C语言中是没有引用传递,这是C++中语言特性,因此在.c文件中使用引用传递会导致程序编译出错。

    展开全文
  • 三种参数传递方式

    千次阅读 2018-10-09 20:39:49
    在函数定义和调用时,三种常见的参数传递方式: 1.传值 2.传指针 3.传引用 下面给出一个例子说明参数传递的三种方式 #include&lt;iostream&gt; using namespace std; void swap1(int a,int b) {...

    在函数定义和调用时,有三种常见的参数传递方式:

    1.传值

    2.传指针

    3.传引用

     

    下面给出一个例子说明参数传递的三种方式

    #include<iostream>
    
    using namespace std;
    
    void swap1(int a,int b)
    {
        int t;
        t=a;
        a=b;
        b=t;
    }
    
    void swap2(int* a,int* b)
    {
        int t;
        t=*a;
        *a=*b;
        *b=t;
    }
    
    void swap3(int &a,int &b)
    {
        int t;
        t=a;
        a=b;
        b=t;
    }
    
    
    int main()
    {
        int x=10,y=20;
        swap1(x,y);
        cout<<x<<' '<<y<<endl;
        swap2(&x,&y);
        cout<<x<<' '<<y<<endl;
        swap3(x,y);
        cout<<x<<' '<<y<<endl;
        return 0;
    }

     

    特别说明:数组参数的传递方式属于特殊情况。数组作为形参按传值方式声明,但实际传递的是数组的首地址(即数组名),使得形参数组和实参数组共用同一组内存单元。

    因此性参数组所作的任何改变相当于在实参数组中进行相应的处理

     

    展开全文
  • C++中函数调用时的三种参数传递方式详解

    万次阅读 多人点赞 2017-08-31 20:44:51
    原文地址:http://blog.csdn.net/cocohufei/article/details/6143476;  ...   在C++中,参数传递方式是“实虚结合”。 按值传递(pass by value) 地址传递(pass by pointer) 引用传递(pass b...

    原文地址:http://blog.csdn.net/cocohufei/article/details/6143476; 

    http://blog.chinaunix.net/uid-21411227-id-1826834.html

     

    在C++中,参数传递的方式是“实虚结合”。

    • 按值传递(pass by value)
    • 地址传递(pass by pointer)
    • 引用传递(pass by reference)

    按值传递的过程为:首先计算出实参表达式的值,接着给对应的形参变量分配一个存储空间,该空间的大小等于该形参类型的,然后把以求出的实参表达式的值一一存入到形参变量分配的存储空间中,成为形参变量的初值,供被调用函数执行时使用。这种传递是把实参表达式的值传送给对应的形参变量,故称这种传递方式为“按值传递”。

    使用这种方式,调用函数本身不对实参进行操作,也就是说,即使形参的值在函数中发生了变化,实参的值也完全不会受到影响,仍为调用前的值。

    /* 
      pass By value 
    */  
    #include <iostream>  
    using namespace std;  
    void swap(int,int);  
    int main()  
    {  
        int a = 3, b = 4;  
        cout << "a = " << a << ", b = "  
        << b << endl;  
        swap(a,b);  
        cout << "a = " << a << ", b = "  
        << b << endl;  
        return 0;  
    }  
    void swap(int x, int y)  
    {  
         int t = x;  
         x = y;  
         y = t;  
    }  
    

    输出:

    如果在函数定义时将形参说明成指针,对这样的函数进行调用时就需要指定地址值形式的实参。这时的参数传递方式就是地址传递方式。

    地址传递与按值传递的不同在于,它把实参的存储地址传送给对应的形参,从而使得形参指针和实参指针指向同一个地址。因此,被调用函数中对形参指针所指向的地址中内容的任何改变都会影响到实参。

    #include <iostream>
    
    using namespace std;
    
    void swap(int*, int*);
    int main(){
    	int a = 3, b = 4;
    	cout << "a=" << a << ", b=" << b << endl;
    	swap(&a, &b);
    	cout << "a=" << a << ", b=" << b << endl;
    	system("pause");
    	return 0;
    }
    
    void swap(int *x, int *y){
    	int t = *x;
    	*x = *y;
    	*y = t;
    }

    输出:

    按值传递方式容易理解,但形参值的改变不能对实参产生影响。

    地址传递方式虽然可以使得形参的改变对相应的实参有效,但如果在函数中反复利用指针进行间接访问,会使程序容易产生错误且难以阅读。

    如果以引用为参数,则既可以使得对形参的任何操作都能改变相应的数据,又使得函数调用显得方便、自然。引用传递方式是在函数定义时在形参前面加上引用运算符“&”。

    #include <iostream>
    
    using namespace std;
    
    void swap(int&, int&);
    int main(){
    	int a = 3, b = 4;
    	cout << "a=" << a << ", b=" << b << endl;
    	swap(a, b);
    	cout << "a=" << a << ", b=" << b << endl;
    	system("pause");
    	return 0;
    }
    
    void swap(int &x, int &y){
    	int t = x;
    	x = y;
    	y = t;
    }

    输出:

     

    一、 函数参数传递机制的基本理论

      函数参数传递机制问题在本质上是调用函数(过程)和被调用函数(过程)在调用发生时进行通信的方法问题。基本的参数传递机制有两种:值传递和引用传递。以下讨论称调用其他函数的函数为主调函数,被调用的函数为被调函数。

      值传递(passl-by-value)过程中,被调函数的形式参数作为被调函数的局部变量处理,即在堆栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本。值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值。

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

    二、 C语言中的函数参数传递机制

      在C语言中,值传递是唯一可用的参数传递机制。但是据笔者所知,由于受指针变量作为函数参数的影响,有许多朋友还认为这种情况是引用传递。这是错误的。请看下面的代码:

    #include <iostream>
    
    using namespace std;
    
    int swap(int *x, int *y)
    {
    	int temp;
    	temp = *x; 
    	*x = *y; 
    	*y = temp;
    	return temp;
    }
    
    void main()
    {
    
    	int a = 1, b = 2;
    	int *p1 = &a;
    	int *p2 = &b;
    	swap(p1, p2);
    }

      函数swap以两个指针变量作为参数,当main()调用swap时,是以值传递的方式将指针变量p1、p2的值(也就是变量a、b的地址)放在了swap在堆栈中为形式参数x、y开辟的内存单元中。

     这里我们可以得到以下几点:

      1. 进程的堆栈存储区是主调函数和被调函数进行通信的主要区域。

      2. C语言中参数是从右向左进栈的。

      3. 被调函数使用的堆栈区域结构为:

        局部变量(如temp)

        返回地址

        函数参数

        低地址

        高地址

      4. 由主调函数在调用后清理堆栈。

      5. 函数的返回值一般是放在寄存器中的。

      这里尚需补充说明几点:一是参数进栈的方式。对于内部类型,由于编译器知道各类型变量使用的内存大小故直接使用push指令;对于自定义的类型(如structure),采用从源地址向目的(堆栈区)地址进行字节传送的方式入栈。二是函数返回值为什么一般放在寄存器中,这主要是为了支持中断;如果放在堆栈中有可能因为中断而被覆盖。三是函数的返回值如果很大,则从堆栈向存放返回值的地址单元(由主调函数在调用前将此地址压栈提供给被调函数)进行字节传送,以达到返回的目的。对于第二和第三点,《Thinking in C++》一书在第10章有比较好的阐述。四是一个显而易见的结论,如果在被调函数中返回局部变量的地址是毫无意义的;因为局部变量存于堆栈中,调用结束后堆栈将被清理,这些地址就变得无效了。

    三、 C++语言中的函数参数传递机制

       众所周知,在c++中调用函数时有三种参数传递方式:

     (1)传值调用;

     (2)传址调用(传指针);

     (3)引用传递;

        实际上,还有一种参数传递方式,就是全局变量传递方式。这里的“全局”变量并不见得就是真正的全局的,所有代码都可以直接访问的,只要这个变量的作用域足够这两个函数访问就可以了,比如一个类中的两个成员函数可以使用一个成员变量实现参数传递,或者使用static关键字定义,或者使用namespace进行限制等,而这里的成员变量在这种意义上就可以称作是“全局”变量(暂时还没有其它比“全局”更好的词来描述)。当然,可以使用一个类外的真正的全局变量来实现参数传递,但有时并没有必要,从工程上讲,作用域越小越好。这种方式有什么优点呢?

     效率高!

     的确,这种效率是所有参数传递方式中效率最高的,比前面三种方式都要高,无论在什么情况下。但这种方式有一个致命的弱点,那就是对多线程的支持不好,如果两个进程同时调用同一个函数,而通过全局变量进行传递参数,该函数就不能够总是得到想要的结果。

     

     下面再分别讨论上面三种函数传递方式。

        1. 从功能上。按值传递在传递的时候,实参被复制了一份,然后在函数体内使用,函数体内修改参数变量时修改的是实参的一份拷贝,而实参本身是没有改变的,所以如果想在调用的函数中修改实参的值,使用值传递是不能达到目的的,这时只能使用引用或指针传递。例如,要实现两个数值交换。

     void swap(int a  int b) 

     void main(){

         int a=1  b=2 

         swap(a b) 

     }

     这样,在main()函数中的a b值实际上并没有交换,如果想要交换只能使用指针传递或引用传递,如:

     void swap(int *a  int *b) 

     或

     void swap(int &a  int &b)

     

       2.从传递效率上。这里所说传递效率,是说调用被调函数的代码将实参传递到被调函数体内的过程,正如上面代码中,这个过程就是函数main()中的a b传递到函数swap()中的过程。这个效率不能一概而论。对于内建的int  char   short long float等4字节或以下的数据类型而言,实际上传递时也只需要传递1-4个字节,而使用指针传递时在32位cpu中传递的是32位的指针,4个字节,都是一条指令,这种情况下值传递和指针传递的效率是一样的,而传递double  long long等8字节的数据时,在32位cpu中,其传值效率比传递指针要慢,因为8个字节需要2次取完。而在64位的cpu上,传值和传址的效率是一样的。再说引用传递,这个要看编译器具体实现,引用传递最显然的实现方式是使用指针,这种情况下与指针的效率是一样的,而有些情况下编译器是可以优化的,采用直接寻址的方式,这种情况下,效率比传值调用和传址调用都要快,与上面说的采用全局变量方式传递的效率相当。

         再说自定义的数据类型,class  struct定义的数据类型。这些数据类型在进行传值调用时生成临时对象会执行构造函数,而且当临时对象销毁时会执行析构函数,如果构造函数和析构函数执行的任务比较多,或者传递的对象尺寸比较大,那么传值调用的消耗就比较大。这种情况下,采用传址调用和采用传引用调用的效率大多数下相当,正如上面所说,某些情况下引用传递可能被优化,总体效率稍高于传址调用。

        3. 从执行效率上讲。这里所说的执行效率,是指在被调用的函数体内执行时的效率。因为传值调用时,当值被传到函数体内,临时对象生成以后,所有的执行任务都是通过直接寻址的方式执行的,而指针和大多数情况下的引用则是以间接寻址的方式执行的,所以实际的执行效率会比传值调用要低。如果函数体内对参数传过来的变量进行操作比较频繁,执行总次数又多的情况下,传址调用和大多数情况下的引用参数传递会造成比较明显的执行效率损失。

     综合2、3两种情况,具体的执行效率要结合实际情况,通过比较传递过程的资源消耗和执行函数体消耗之和来选择哪种情况比较合适。而就引用传递和指针传递的效率上比,引用传递的效率始终不低于指针传递,所以从这种意义上讲,在c++中进行参数传递时优先使用引用传递而不是指针。

        4. 从类型安全上讲。值传递与引用传递在参数传递过程中都执行强类型检查,而指针传递的类型检查较弱,特别地,如果参数被声明为 void ,那么它基本上没有类型检查,只要是指针,编译器就认为是合法的,所以这给bug的产生制造了机会,使程序的健壮性稍差,如果没有必要,就使用值传递和引用传递,最好不用指针传递,更好地利用编译器的类型检查,使得我们有更少的出错机会,以增加代码的健壮性。

     这里有个特殊情况,就是对于多态的情况,如果形参是父类,而实参是子类,在进行值传递的时候,临时对象构造时只会构造父类的部分,是一个纯粹的父类对象,而不会构造子类的任何特有的部分,因为办有虚的析构函数,而没有虚的构造函数,这一点是要注意的。如果想在被调函数中通过调用虚函数获得一些子类特有的行为,这是不能实现的。

     5. 从参数检查上讲。一个健壮的函数,总会对传递来的参数进行参数检查,保证输入数据的合法性,以防止对数据的破坏并且更好地控制程序按期望的方向运行,在这种情况下使用值传递比使用指针传递要安全得多,因为你不可能传一个不存在的值给值参数或引用参数,而使用指针就可能,很可能传来的是一个非法的地址(没有初始化,指向已经delete掉的对象的指针等)。所以使用值传递和引用传递会使你的代码更健壮,具体是使用引用还是使用,最简单的一个原则就是看传递的是不是内建的数据类型,对内建的数据类型优先使用值传递,而对于自定义的数据类型,特别是传递较大的对象,那么请使用引用传递。

        6. 从灵活性上。无疑,指针是最灵活的,因为指针除了可以像值传递和引用传递那样传递一个特定类型的对象外,还可以传递空指针,不传递任何对象。指针的这种优点使它大有用武之地,比如标准库里的time( )函数,你可以传递一个指针给它,把时间值填到指定的地址,你也可以传递一个空指针而只要返回值。

     

    以上讨论了四种参数传递方式的优缺点,下面再讨论一下在参数传递过程中一些共同的有用的技术。

     1. const关键字。当你的参数是作为输入参数时,你总不希望你的输入参数被修改,否则有可能产生逻辑错误,这时可以在声明函数时在参数前加上const关键字,防止在实现时意外修改函数输入,对于使用你的代码的程序员也可以告诉他们这个参数是输入,而不加const关键字的参数也可能是输出。例如strlen,你可以这样声明

         int strlen(char str) 

     功能上肯定没有什么问题,但是你想告诉使用该函数的人,参数str是一个输入参数,它指向的数据是不能被修改的,这也是他们期望的,总不会有人希望在请人给他数钱的时候,里面有张100的变成10块的了,或者真钞变成假钞了,他们希望有一个保证,说该函数不会破坏你的任何数据,声明按如下方式便可让他们放心:

         int strlen(const char str) 

     可不可以给str本身也加一个限制呢,如果把地址改了数得的结果不就错了吗?总得给人点儿自由吧,只要它帮你数钱就行了,何必介意他怎么数呢?只要不破坏你的钱就ok了,如果给str一个限制,就会出现问题了,按照上面的声明,可以这样实现:

    int strlen(const char str){    
    	int cnt;
    	if(!str) 
    		return 0;
    	cnt = 0;
    	while((str++)){
    		++cnt; 
    	}
    	return cnt;
    
    }

     可是,如果你硬要把声明改成

         int strlen(const char const str) 

     上面的函数肯定就运行不了了,只能改用其它的实现方式,但这个不是太有必要。只要我们保护好我们的钱就行了,如果它数不对,下次我次不让它数,再换个人就是了。

     

    对于成员函数,如果我们要显示给客户代码说某个成员函数不会修改该对象的值,只会读取某些内容,也可以在该函数声明中加一个const.

     class    person

     {......

       public:

         unsigned char age( void ) const   // 看到const就放心了,这个函数肯定不会修改m_age

       private:

         unsigned char m_age    // 我认为这个类型已经足够长了,如果觉得不改可以改为unsigned long

     }

         2. 默认值。个人认为给参数添加一个默认值是一个很方便的特性,非常好用,这样你就可以定义一个具有好几个参数的函数,然后给那些不常用的参数一些默认值,客户代码如果认为那些默认值正是他们想要的,调用函数时只需要填一些必要的实参就行了,非常方便,这样就省去了重载好几个函数的麻烦。可是我不明白c#为什么把这个特性给去掉了,可能是为了安全,这样就要求每次调用函数时都要显示地给函数赋实参。所以要注意,这可是个双刃剑,如果想用使刀的招跟对手武斗,很可能伤到自己。

        3.参数顺序。当同个函数名有不同参数时,如果有相同的参数尽量要把参数放在同一位置上,以方便客户端代码。

    c++ 中经常使用的是常量引用,如将swap2改为:

        Swap2(const int& x; const int& y)

      这时将不能在函数中修改引用地址所指向的内容,具体来说,x和y将不能出现在"="的左边。

     

     

     

    展开全文
  • 主要介绍了python传递参数方式,实例总结了Python常用参数传递方式,具有一定参考借鉴价值,需要的朋友可以参考下
  • 函数参数传递的三种方式

    千次阅读 2019-05-15 20:28:58
    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
    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(2,2);
    pt1和pt2都具有(12,12)的值。
    引用必须在定义时马上被初始化,因为它必须是某个东西的同义词。你不能先定义一个引用后才
    初始化它。例如下面语句是非法的:
    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;


    作者:魏波-
    来源:CSDN
    原文:https://blog.csdn.net/weibo1230123/article/details/75541862
    版权声明:本文为博主原创文章,转载请附上博文链接!

    展开全文
  • spring MVC 的参数传递方式

    千次阅读 2017-11-15 15:23:27
     在使用spring的项目中,前台传递参数到后台是经常遇到的事, 我们必须熟练掌握一些常用参数传递方式和注解的使用,废话少说,直接上正文。 1. @requestMapping: 类级别和方法级别的注解, 指明前后台解析的路径...
  • SpringBoot前后端分离参数传递方式总结

    千次阅读 多人点赞 2020-11-26 21:39:50
    因为总是需要使用不同的参数传递方式,所以特地来总结一下SpringBoot中常用的传递参数的方式。 SpringBoot参数传递 注意:虽然Restful风格很流行,但是大部分还是主要是GET和POST的内容,所以这里只是列举GET和POST...
  • 汇编主程序与子程序参数传递方式

    千次阅读 2018-12-22 10:57:43
    实现方法是在主程序中把要传递参数放在某一指定的寄存器中,然后从子程序中取出指定的寄存器参数。 2、约定单元法: 入口参数和出口参数都放在事先约定好的单元中,子程序可以直接访问该变量。 优点:不占用...
  • 1、 C语言中实参和形参之间的数据传递是单向的“值传递”,单向传递,只能由实参传给形参,反之不能。 2、 被调用函数的形参只有函数被调用时才会临时分配存储单元,一旦调用结束占用的内存便会被释放。 3、 ...
  • 一、请求参数传递方式 1、GET 请求方式 GET 请求方式参数放置在请求地址中进行传递。 xhr.open('get', 'http://www.example.com?name=zhangsan&age=20'); 传递GET 请求参数代码示例: <!DOCTYPE html> ...
  • java 传递参数的两种方式

    万次阅读 多人点赞 2015-10-19 15:39:28
    Java中没有指针,所以也没有引用传递了,仅仅传递不过可以通过对象的方式来实现引用传递 类似java没有多继承 但可以用多次implements 接口实现多继承的功能  值传递:方法调用时,实际参数把它的值传递给对应...
  • 参见 http://blog.csdn.net/xcl168 Android开发中,在不同模块(如Activity)间经常会各种各样的数据需要相互传递,我把常用的几种 方法都收集到了一起。它们各有利弊,各自己的应用场景。 我现在把它们集中到...
  • java积累---HttpDelete请求方式传递参数

    万次阅读 2019-04-30 16:27:03
    // 中文处理 StringEntity se = new StringEntity(json, Consts.UTF_8); ... ...HttpPost、HttpPut继承了HttpEntityEnclosingRequestBase类,所以setEntity方法。详情请自行查看源码。 查看httpc...
  • JSP中传递参数方式的总结

    千次阅读 2018-03-03 17:12:12
    Jsp中比较常用传递参数的方法:1、form表单:<form> 标签用于为用户输入创建 HTML 表单。表单能够包含 input 元素,比如文本字段、复选框、单选框、提交按钮等等。表单还可以包含 menus、textarea、fieldset、...
  • 入门学习Linux常用必会60个命令实例详解doc/txt

    千次下载 热门讨论 2011-06-09 00:08:45
    这些设备名称的命名都是规则的,可以用“推理”的方式把设备名称找出来。例如,/dev/hda1这个 IDE设备,hd是Hard Disk(硬盘)的,sd是SCSI Device,fd是Floppy Device(或是Floppy Disk?)。a代表第一个设备,通常IDE...
  • SpringMVC后台接收请求参数的几种方式源码。总结了常用的注解,介绍GET和POST请求方式下的参数传递方法。
  • Shell脚本中参数传递方法常用有8种

    万次阅读 2016-01-23 18:29:32
    Shell脚本中参数传递方法常用有8种 1. $# 传递到脚本的参数个数 2. $* 以一个单字符串显示所有向脚本传递的参数变量。与位置变量不同,此选项参数可超过9个 3. $$ 脚本运行的当前进程ID号 4. $! 后台...
  • 在SpringBoot整合Mybatis中,传递多个参数方式和Spring整合Mybatis略微有点不同,下面主要总结三种常用方式 一、顺序传参法 Mapper层: 传入需要的参数 public interface GoodsMapper { public Goods ...
  • Shell脚本通过参数传递参数

    千次阅读 2020-02-06 18:08:11
    Linux常用的命令都可指定参数名和参数值,然而我们怎样才能给自己的shell脚本也采用参数名和参数值这样的方式来获取参数值呢?而不是通过$1,$2这种方式进行获取。下面的例子定义了短参数名和长参数名两种获取参数值...
  • 在定义路由URL时,可以使用正则表达式提取参数的方法从URL中获取请求参数,Django会将提取的参数直接传递到视图的传入参数中。 未命名参数按定义顺序传递, 如 url(r'^weather/([a-z]+)/(\d{4})/$', views....
  • Java基础知识面试题(2020最新版)

    万次阅读 多人点赞 2020-02-19 12:11:27
    原理是什么Java语言哪些特点什么是字节码?采用字节码的最大好处是什么什么是Java程序的主类?应用程序和小程序的主类何不同?Java应用程序与小程序之间那些差别?Java和C++的区别Oracle JDK 和 OpenJDK 的...
  • 函数的参数作为引用 Python 唯一支持的参数传递模式是共享传参(call by sharing)。...”这么说没错,但是会引起误解,因为在旧式语言中,最常用参数传递模式按值传递(函数得到参数的副本)和按引...
  • http之GET请求的传递参数方式

    万次阅读 2019-09-23 13:43:32
    第一种:直接在URL后面加参数: localhost:21811/Handler1.ashx?...localhost:21811/Handler1.ashx页面,然后还会传递id 和name 两个参数过去; 例如:超链接 第三种:通过js方法传递:用户点击这个button按钮,触发o...
  • python参数传递

    千次阅读 2018-07-12 21:20:54
    我们使用 b[:] 的方式 就相当于把 a 数组的每一个元素对应的拷贝到 b 中去所以就另开了一块空间存储,这时的a ,b是互不影响的。 这里涉及到一个知识点就是python参数引用的问题(传值\传地址) 如果函数收到的...
  • Hadoop 传递参数的四种方式

    千次阅读 2017-08-24 12:01:38
     这个是mappe task 和reduce task log打印出来的信息,说明参数传递成功  至于其他的基本类型的设置方式与String类型类似,并且其实还是转化为String类型进行存取,例如int型: /** * Set the value...
  • Mybatis使用之参数传递

    千次阅读 2015-05-20 16:41:24
    摘要: 主要记录Mybatis是如何映射传递的参数的。分四种来记录:1、java基本类型的传递、2、Java对象形式传递 3、多参数传递4、集合类型参数传递
  • Python中函数传递参数有四种形式

    千次阅读 2017-06-06 14:19:53
    Python中函数传递参数有四种形式 fun1(a,b,c)  fun2(a=1,b=2,c=3)  fun3(*args)  fun4(**kargs) 四种中最常见是前两种,基本上一般点的教程都会涉及,后两种一般很少单独出现,常用在混合模式中 ...
  • oozie常用的系统常量 场景:HUE执行任务需要从外部传入参数,不能在脚本写死,比较麻烦 WorkFlow传静态参数 执行的脚本代码如下 CREATE EXTERNAL TABLE ${hivevar:database}.${hivevar:tableName}${pt_tab}...
  • c++中的参数传递问题

    千次阅读 2015-12-13 00:07:32
    众所周知,在C++中调用函数时三种参数传递方式:  (1)传值调用;  (2)传址调用(传指针);  (3)引用传递;  实际上,还有一种参数传递方式,就是全局变量传递方式。这里的“全局”变量并不见得...
  • shell脚本通过参数传递参数

    千次阅读 2019-09-24 16:53:18
    Linux常用的命令都可指定参数名和参数值,然而我们怎样才能给自己的shell脚本也采用参数名和参数值这样的方式来获取参数值呢?而不是通过$1,$2这种方式进行获取。下面的例子定义了短参数名和长参数名两种获取参数值...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 394,799
精华内容 157,919
关键字:

常用的参数传递方式有