精华内容
下载资源
问答
  • 函数参数传递的两种方式——值传递和引用传递
    万次阅读 多人点赞
    2018-10-23 15:50:05

    参考原文详细说明:https://www.cnblogs.com/codingmengmeng/p/5865510.html

    一、值传递

    值传递包括实实在在的值传递以及指针传递(指针传递参数本质上是值传递的方式,它所传递的是一个地址值),传递的都是实参的一个拷贝。

    1、实实在在的“值”传递

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    void function(int num){
    	//改变num的值
    	num = 100;
    }
    
    int main()
    {
    	int number;
    	number = 1;
    	function(number);
    	cout << number << endl;
    	return 0;
    }

    这样的值传递只能把一个函数中的值传递给另一个函数,当该值在被调函数中发生改变时,在原来的函数中并不会发生改变。因为被调函数的形参只有函数被调用的时候才会临时分配单元,一旦调用结束占用的内存便会释放,所以调用的函数中存储number的地址跟被调函数中num的地址不是一回事。

    那如果想让number通过被调函数改变怎么做呢?第一种是使用指针形式的值传递,第二种是使用引用传递。

    2、指针传递

    指针传递是通过地址间接的改变了实参的值。

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    void function(int* num){
    	//通过改变num对应地址的值来实现值的改变:形参num是一个指针,传递过来的是一个地址值,解引用即可访问到这个地址值映射的值
    	*num = 100;
    }
    
    int main()
    {
    	int number;
    	number = 1;
    	function(&number);
    	cout << number << endl;
    	return 0;
    }

    二、引用传递

    对引用的操作等于是对其指定的对象进行操作,当将实参传递给形参时,形参就指向了实参(形参与实参同义,是实参的一个别名)。

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    void function(int& num){
    	//通过引用改变num的值
    	num = 100;
    }
    
    int main()
    {
    	int number;
    	number = 1;
    	function(number);
    	cout << number << endl;
    	system("pause");
    	return 0;
    }

     

    更多相关内容
  • 函数参数的两种传递方式

    千次阅读 2020-03-27 19:02:11
    当调用函数时,两种向函数传递参数方式: 一、传值调用 该方法把参数的实际值复制给函数的形式参数。在这种情况下,修改函数内的形式参数不会影响实际参数。 默认情况下,C 语言使用传值调用方法来传递参数。...

    如果函数要使用参数,则必须声明接受参数值的变量。这些变量称为函数的形式参数。

    形式参数就像函数内的其他局部变量,在进入函数时被创建,退出函数时被销毁。
    当调用函数时,有两种向函数传递参数的方式:

    一、传值调用

    该方法把参数的实际值复制给函数的形式参数。在这种情况下,修改函数内的形式参数不会影响实际参数。
    默认情况下,C 语言使用传值调用方法来传递参数。一般来说,这意味着函数内的代码不会改变用于调用函数的实际参数
    函数 swap() 定义如下:

    /* 函数定义 */
    void swap(int x, int y)
    {
       int temp;
    
       temp = x; /* 保存 x 的值 */
       x = y;    /* 把 y 赋值给 x */
       y = temp; /* 把 temp 赋值给 y */
      
       return;
    }
    

    现在,让我们通过传递实际参数来调用函数 swap():

    #include <stdio.h>
     
    /* 函数声明 */
    void swap(int x, int y);
     
    int main ()
    {
       /* 局部变量定义 */
       int a = 100;
       int b = 200;
     
       printf("交换前,a 的值: %d\n", a );
       printf("交换前,b 的值: %d\n", b );
     
       /* 调用函数来交换值 */
       swap(a, b);
     
       printf("交换后,a 的值: %d\n", a );
       printf("交换后,b 的值: %d\n", b );
     
       return 0;
    }
    

    当上面的代码被编译和执行时,它会产生下列结果:

    交换前,a 的值: 100
    交换前,b 的值: 200
    交换后,a 的值: 100
    交换后,b 的值: 200
    
    

    上面的实例表明了,虽然在函数内改变了 a 和 b 的值,但是实际上 a 和 b 的值没有发生变化。

    二、引用调用

    通过指针传递方式,形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作。
    传递指针可以让多个函数访问指针所引用的对象,而不用把对象声明为全局可访问。
    还是以上述代码为例:

    /* 函数定义 */
    void swap(int *x, int *y)
    {
       int temp;
       temp = *x;    /* 保存地址 x 的值 */
       *x = *y;      /* 把 y 赋值给 x */
       *y = temp;    /* 把 temp 赋值给 y */
      
       return;
    }
    

    现在,让我们通过引用传值来调用函数 swap():

    #include <stdio.h>
     
    /* 函数声明 */
    void swap(int *x, int *y);
     
    int main ()
    {
       /* 局部变量定义 */
       int a = 100;
       int b = 200;
     
       printf("交换前,a 的值: %d\n", a );
       printf("交换前,b 的值: %d\n", b );
     
       /* 调用函数来交换值
        * &a 表示指向 a 的指针,即变量 a 的地址
        * &b 表示指向 b 的指针,即变量 b 的地址
       */
       swap(&a, &b);
     
       printf("交换后,a 的值: %d\n", a );
       printf("交换后,b 的值: %d\n", b );
     
       return 0;
    }
    

    当上面的代码被编译和执行时,它会产生下列结果:

    交换前,a 的值: 100
    交换前,b 的值: 200
    交换后,a 的值: 200
    交换后,b 的值: 100
    

    上面的实例表明了,与传值调用不同,引用调用在函数内改变了 a 和 b 的值,实际上也改变了函数外 a 和 b 的值。

    展开全文
  • 浅谈Python3中函数参数传递方式

    千次阅读 2018-02-27 23:25:21
    之前在看北理工嵩天等老师的python3的课程,在第五周中老师讲到了函数的调用传递。老师讲了这样一个例子 #处理多个银行账户的余额信息 def addInterest(balances, rate): for i in range(len(balances)): ...

    之前在看北理工嵩天等老师的python3的课程,在第五周中老师讲到了函数的调用传递。老师讲了这样一个例子

    #处理多个银行账户的余额信息
    def addInterest(balances, rate):  
        for i in range(len(balances)):  
            balances[i] = balances[i] * (1+rate)  
    def test():  
        amounts = [1000, 105, 3500, 739]  
        rate = 0.05  
        addInterest(amounts, rate)  
        print(amounts)  
    
    test()  
    

    在这个例子中可以看到为了处理多个银行账户设置了amounts这个列表,老师的原话是这样的:

    “在test函数中一开始设置了amounts为4个值的列表,然后将amounts作为第一个参数传递给函数addInterest,并调用执行该函数,最后打印输出amounts的结果,运行结果如下:

    [1050.0,110.25,3675.0,775.95] 
    

    然后礼欣老师得出结论,以下为原话

    在这个例子中可以看到,amounts变量的值好像是被修改了,但是函数是不能改变变量本身即amounts的

    这里的背景色是

    接下来是分析下函数的执行过程,过程如下图
    addinterest()函数.png-267.9kB

    分析原话如下

    “接下来分析下整个执行过程,查看amounts输出结果是如何发生变化的。首先函数test的前两条语句建立了两个变量amounts和rate,然后控制传递给addinterest,这里amounts是一个包含4个整数类型值的列表对象,以实参的形式传递给函数addinterest形参balances,下一步执行函数addinterest,从0到length-1范围执行循环,并更新balances的值。”

    重点来了:原话如下

    “图中旧值 [1000, 105, 3500, 739]
    并没有改变,只是Python又创建了一组新值[1050.0,110.25,3675.0,775.95]
    ,并且使列表对象指向该组新值,而旧值会在Python的垃圾数据回收的时候被清除掉③,从图中我们可以清楚的看出,为什么包含列表参数的程序addinterest修改了列表的值?但程序addinterest结束时存储在amounts中的是新balances的值,实际上变量amounts从来没有被改变过。

    它(amounts,作者注)仍然指向的是调用addinterest函数之前的同一个列表,只是当控制返回到调用函数中时,列表呈现了被修改的状态”②

    最后是得出结论,原话如下:

    “通过上述过程我们可以了解到:Python的参数是通过值来传递的。但是如果变量是可变对象,比如是列表或者是图形对象,返回到调用程序后,该对象会呈现出被修改的状态。”

    ^_^
    注:课程原始视频部分结束。

    看了老师的这段讲解之后产生了很多疑问:在前面(①处)讲的amounts是不能被修改的,但是在(②处)又说列表呈现了被修改的状态,这不是自相矛盾吗?在(③)处讲列表创建了新值并且使列表指向了新值,这里不就是说amounts发生了改变吗?怎么能说没变呢?最后结论也是列表呈现出了被修改的状态。这个结论云山雾绕,看得人似懂非懂。

    那在Python3中参数变量是列表,在调用函数完返回后到底是被修改了还是没被修改呢?

    为了弄清这个问题,我做了一个实验,id()可以查看变量在内存中的地址,这个值相当于一个对象的“身份证”。

    # 处理多个银行账户的余额信息
    def addInterest(balances, rates):
    print()
    print("第二处", id(balances))
        for i in range(len(balances)):
            balances[i]= balances[i]*(1+rates)
            print()
            print("第三处",id(balances))
    def test():
        amounts = [1000,105,3500,739]
        print()
        print("第一处",id(amounts))
        rate = 0.05
        addInterest(amounts, rate)
        print()
        print(amounts)
        print()
        print("第四处",id(amounts))
    test()
    

    输出结果:

    第一处 41203656
    
    第二处 41203656
    
    第三处 41203656
    
    第三处 41203656
    
    第三处 41203656
    
    第三处 41203656
    
    [1050.0, 110.25, 3675.0, 775.95]
    
    第四处 41203656
    

    在这个实验中可以清楚的看到,amounts这个对象的身份证号码在整个程序运行过程中从未变过,而非视频中老师讲的创建了新的列表对象。所以amounts作为一个列表对象在程序运行过程中是被直接修改了,是的就是直接被修改了,而非指向新balances的值。为什么可以得出这一结论?我们可以看下第一、三处的id,在未进入函数之前id是41203656(第一处),进入函数之后对象id仍然未变,函数运行完返回之后对象id仍然未变!

    所以结论应该这样写会比较清楚:

    改变参数值值的函数:
    实参传给形参时,python的参数是通过值来传递的;
    如果变量是可变对象(如列表或者图形对象),该对象会在函数中会被直接修改,返回到调用程序后也是被修改后的状态。

    那是不是Python3中函数都是像这种传递方式呢?我们对课程视频中的另一个例子做一个简单的修改。

     # 计算单个银行账户余额
    def addinterest(balance, rate):
        print("第二处", id(balance))
        newBalance = balance * (1 + rate)
        print()
        print("第三处", id(balance))
        print()
        print("第四处", id(newBalance))
        return newBalance
    
    
    def main():
        amount = 1000
        print("第一处", id(amount))
        print()
        rate = 0.05
        amount = addinterest(amount, rate)
        print()
        print("第五处", id(amount))
        print()
        print(amount)
        print("第六处", id(amount))
    
    
    main()
    

    运行结果如下:

    第一处 33533648
    
    第二处 33533648
    
    第三处 33533648
    
    第四处 33563344
    
    第五处 33563344
    
    1050.0
    第六处 33563344
    

    不是说好的直接修改的吗?怎么身份证又变了?其实这里的对象amount是个常数,即为不可变对象,当在函数中要对对象进行处理时,由于对象不可变,只能新建一个新对象,然后return出新的对象了。

    这个也就是目前网络上大部分博客的结论:
    1、不可变对象作为函数参数,Python通过值传递;
    2、 可变对象作为函数参数,Python通过引用传递。
    注:Python中,数值类型(int和float)、字符串str、元组tuple都是不可变类型。而列表list、字典dict、集合set是可变类型。
    (但是也有博客把这两个结论搞反了)

    但是也有博客提出了一个类似这样的例子

    def change(val):
        val = val + [10]
    nums = [0, 1]
    change(nums)
    print(nums)
    

    输出结果为

    [0, 1]
    

    其实这里是写的不严谨,不能直接用加号添加列表元素
    可以改为这样

    def change(val):
        newval = [10]
        val= val + newval
    
    nums = [0, 1]
    change(nums)
    print(nums)
    

    但是输出结果还是

    [0, 1]
    

    难道上面的结论不对吗?
    其实这里要补充另外一种情况:对于可变对象作为函数参数,且参数不指向其他对象时,相当于引用传递;否则,若参数指向其他对象,则对参数变量的操作并不影响原变量的对象值

    函数里的参数变量val指向了与nums不同的内存变量,所以函数里的参数变量val不影响原变量nums的值
    3.png-23.8kB
    **这也是因为python的特性” 变量无类型,对象有类型 “。
    变量是对内存空间的引用,当参数变量和原变量指向不同的内存空间时,操作互不影响。**

    用下面这个看下

    def change(val):
        newval = [10]
        print("第二处",id(val))
        val = val + newval
        print("第三处",id(val))
    nums = [0, 1]
    print("第一处",id(nums))
    change(nums)
    print("第四处",id(nums))
    print(nums)
    

    运行结果如下:

    第一处 39695944
    第二处 39695944
    第三处 39710024
    第四处 39695944
    [0, 1]
    

    可以看到第一处的nums和第二处的val的内存地址完全一样,然后执行到第三处时,由于函数内VAL重新指向了别的内存变量,所以内存地址不同。但是最后结果要输出变量nums,即第一处第二处内存地址的值,所以和第三处的val就没关系了。其实这里的val是没有返回值的。

    想要直接在列表中添加元素可以写成这样:

    def change(val):
        val.append(10)
    nums = [0, 1]
    change(nums)
    print(nums)
    

    输出结果是

    [0, 1, 10]
    

    关于变量无类型,对象有类型可以这样理解:只有放在内存空间中的对象(也就是数据)才有类型,而变量是没有类型的。

    如果还是不明白可以做这样一种比喻:变量就好比钓鱼者,湖水就好像内存,里面有各种各样的鱼,它们就是对象。钓鱼者(变量)的任务就是用某种方式把自己和鱼(对象)通过鱼线连接起来。那么,鱼(对象)是有类型的,有鲢鱼、鲫鱼、带鱼。钓鱼者(变量)没有类型,他钓到不同类型的鱼(对象)。

    用钓鱼的比喻解释下上面的例子

    def change(val):
        newval = [10]
        val= val + newval
    
    nums = [0, 1]
    change(nums)
    print(nums)
    

    1、钓鱼人已经钓了一桶鱼用nums桶装着,nums桶可以装很多鱼。

    2、现在提着这个nums桶继续在湖里钓鱼,这时候nums桶暂时叫做装鱼桶val,突然钓鱼人钓了一条大鱼,发现装鱼桶val装不下,于是钓鱼人又在渔具店买了另一个大的装鱼桶VAL,把大鱼和之前的鱼一块装了。

    钓鱼活动结束。
    3、最后要看看那个叫nums的桶有哪些鱼,这时候当然只能看之前的情况。

    即这个结论:对于可变对象作为函数参数,且参数不指向其他对象时,相当于引用传递;否则,若参数指向其他对象,则对参数变量的操作并不影响原变量的对象值。

    同样的针对其他两个结论,也可以用这个比喻解释:

    def change( val):
        newval = val + 10
        return  newval
    num = 1
    num = change(num)
    print(num)
    
    1、钓鱼人手上的东西num是个小蚯蚓。
    2、钓鱼人拿着num去湖边钓鱼,小蚯蚓被大鱼吃了,钓鱼人钓到了一条大鱼,钓鱼人拿着鱼回家。
    钓鱼活动结束。
    3、问钓鱼人手上现在拿着什么东西num?当然是一条大鱼。
    
    def change(val):
        val.append(10)
    nums = [0, 1]
    change(nums)
    print(nums)
    

    1、钓鱼人提着一个叫nums的桶,桶里装着2条鱼 2、钓鱼人来到湖边钓鱼,此时桶暂时叫装鱼桶val,钓鱼人钓到了一条鱼放进装鱼桶val。
    钓鱼活动结束。
    3、看看钓鱼人桶里的有几条鱼。

    总结来说:

    **对于不可变对象作为函数参数,相当于C系语言的值传递;
    对于可变对象作为函数参数,且参数不指向其他对象时,相当于C系语言的引用传递。
    对于可变对象作为函数参数,参数指向其他对象,对参数变量的操作不影响原变量的值。**

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

    千次阅读 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
    版权声明:本文为博主原创文章,转载请附上博文链接!

    展开全文
  • C语言函数参数传递详解

    千次阅读 2021-06-02 11:00:20
    1.值传递和指针传递 (1)值传递:即按值传递参数,是将实参变量的值复制一个到临时存储单元中,如果在调用过程中改变了形参的值,不会影响实参变量本身,即实参变量保持调用前的值不变 ...
  • C语言函数参数传递的两种方式:值传递和引用传递1 值传递1.1 实实在在的值传递1.2 指针传递2 引用传递3 字符串变量的函数传递与指针传递3.1 错误示范参考 1 值传递 值传递包括实实在在的值传递和指针传递,指针传递...
  • python函数的四种参数传递方式

    千次阅读 2018-11-09 16:29:56
    fun1(a,b,c) fun2(a=1,b=2,c=3) fun3(*args) fun4(**kargs) ...可以传入任意个参数,这些若干参数都被放到了tuple元组中赋值给行参args,参数的数量上没有了限制,次序。 最为灵活,其是以键值对...
  • C语言中函数参数传递的三种方式

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

    万次阅读 2017-09-04 22:58:51
    C++函数传递参数方式有以下四种: (1) 值传递  当进行值传递时,就是将实参的值复制到形参中,而形参和实参不是同一个存储单元,所以函数调用结束后,实参的值不会发生改变,程序示例如下: #include using ...
  • Shell——函数参数传递

    千次阅读 2020-06-30 17:27:19
    获取函数参数的个数 用户可以通过 系统变量 $# 来获取脚本的参数的个数,当然,函数也是。 [linux@localhost SkySong]$ func() > { > echo "参数个数:$#" > } [linux@localhost SkySong]$ func 1 2 3 4 ...
  • 64位函数参数传递方式

    万次阅读 2018-03-08 18:54:19
    64位函数传参方式
  • 上篇文章《c语言函数传参の结构体数组篇》提到了C语言的函数传参方式,百度了一一一大圈,说两种的,也说三种的,简直把我搞晕了,其中争议的地方就是“引用传递方式。我看好多写三种方式的都把源代码代码贴...
  • C/C++中函数参数传递详解

    千次阅读 多人点赞 2018-07-26 17:06:24
    昨天看了内存管理的有关内容,一点了解,但不是很深入,发现之前写代码时很多细节问题没有注意到,只知道这样做可以实现功能,却不知道为什么可以这样,对于采用自己的方法造成的隐患也未知,更不晓得还有
  • 函数参数三种传递方式的区别

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

    千次阅读 2018-12-25 18:27:08
    按值传递 参数地址传递 引用传递
  • Python中函数传递参数有四种形式

    千次阅读 2019-12-10 15:39:40
    Python中函数传递参数有四种形式 fun1(a,b,c) fun2(a=1,b=2,c=3) fun3(*args) fun4(**kargs) 四种中最常见是前两种,基本上一般点的教程都会涉及,后两种一般很少单独出现,常用在混合模式中 第一种 fun1(a,b,c)...
  • C++中函数调用时的三种参数传递方式详解

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

    万次阅读 多人点赞 2016-05-08 10:37:40
    1.形式参数和实际参数 1.1形式参数 形参出现在被调函数当中,在整个函数体内都可以使用。形参在定义时编译系统并不分配存储空间,只有在调用该函数时才分配内存单元。...传递方式有两种:值传递和地址传
  • VBA函数传递参数方式

    万次阅读 2018-03-04 20:58:03
    VBA函数传递参数值时分为...在VBA中,参数传递的默认方式是Byref,因为本质想法是对于相同命名的参数,在系统中采用同一个数值。 '获取非空行 Function GetNotNullRow(ByVal iStartRow, ByRef iRow) Dim Rng As Ran
  • 结构体作为函数参数传递

    千次阅读 2019-08-23 10:46:48
    结构变量是一个标量,它可以用于其他标量可以使用的任何场合,但把结构体作为参数传递给一个函数要注重效率 例如下面这样一个结构体: #define PRODUCT_SIZE 20 typedef struct{ char product[PRODUCT_SIZE]; ...
  • 1)用寄存器(变量)传递参数, 在参数不多的时候采用这种方式(用的最多)。  附图实现的功能为串口发送ASCII码到上位机。,采用的就是寄存器传递参数方式。 2)用地址表传递参数  在主程序中建立一个地址表...
  • C语言函数返回值与参数传递

    千次阅读 多人点赞 2019-10-26 11:57:43
    C语言的函数中必不可少的就是参数传递,可以采用传值和传指针两种方式。 1.传值的形式:只是将参数值的拷贝传给函数,并非参数本体如: int test(int x,int y) { x=2*y; return x; } int main(void) { int a=0,b...
  • 指针作为函数参数传递一维数组 C 语言中声明了一个数组TYPE array[n],则数组名称array 就了两重含义: 第一,它代表整个数组,它的类型是TYPE[n];...因此,指针作为函数参数传递一维数组4种形式: #incl...
  • Kotlin之函数作为参数传递

    千次阅读 2020-08-29 00:10:09
    1 、Kotlin之函数作为参数传递 我们在写BaseQuickAdapter适配器的时候,时候嵌套多个BaseQuickAdapter,如果最里面的view触发点击事件,我们可以把函数作为参数通过构造函数一层一层传递进去。 ...
  • 从汇编角度看函数参数传递

    千次阅读 2018-06-05 16:11:39
    函数参数传递机制问题在本质上是调用函数过程和被调用函数在调用发生时进行同的方法问题。基本的参数传递机制两种,值传递、引用传递。 值传递: 在值传递过程中,被调函数的形参作为被调函数的局部变量,即在该...
  • c++之指针作为函数参数传递的问题

    万次阅读 多人点赞 2018-09-30 11:23:51
    了这两个概念,就不难理解指针作为函数参数传递的问题。   首先,我们来看下上面的代码中的a 指针和p 指针的内存结构。 我们看到,当我们以a 作为func 函数的参数传递进去的时候,函数复制了这个...
  • 关于指针作为函数参数传递的理解

    千次阅读 多人点赞 2019-04-23 17:30:01
    本来已经把指针和引用的知识都捋清楚了,但是中午编程遇到了一个传递数组的问题,一下想得多了点,然后又。。。。 被值传递,指针传递,引用传递,地址传递这几个概念弄晕了。看了十来篇博客,什么说法都。参考...
  • C\C++中函数参数的三种传递方式

    千次阅读 2018-07-16 09:07:30
    这种传递方式中,实参和形参是两个不同的地址空间,参数传递的实质是将原函数中变量的值,复制到被调用函数形参所在的存储空间中,这个形参的地址空间在函数执行完毕后,会被回收掉。整个被调用函数对形参的操作,只...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,335,889
精华内容 534,355
关键字:

常用的函数参数传递方式有