传值,传指针和传引用区别和联系

传值,传指针和传引用区别和联系

其实,不用分为三类,只有两类即可。传值和传引用。为什么会出现传地址(即传指针)呢?本质就是大家一致对传值和传地址概念的理解错误导致,也是对指针的概念的理解错误导致。

指针:指针就是一个变量,如果非要说是一个特殊的变量也不为过,因为指针的初始化和解引用等不同的操作方式而已。就内存的分布来说,指针和一个变量在内存中存放是没有任何区别的,无非指针存放的是变量的地址。

传值:传值无非就是实参拷贝传递给形参,单向传递(实参->形参),赋值完毕后实参就和形参没有任何联系,对形参的修改就不会影响到实参。

传地址:为什么说传地址也是一种传值呢?因为传地址是把实参地址的拷贝传递给形参。还是一句话,传地址就是把实参的地址复制给形参。复制完毕后实参的地址和形参的地址没有任何联系,对实参形参地址的修改不会影响到实参, 但是对形参地址所指向对象的修改却直接反应在实参中,因为形参指向的对象就是形参的对象。

传引用:传引用本质没有任何实参的拷贝,一句话,就是让另外一个变量也执行该实参。就是两个变量指向同一个对象。这是对形参的修改,必然反映到实参上。

#include<iostream>
using namespace std;

void Value(int n)
{
    cout << "Value(int n)"<< endl;
    cout << "{" << endl;
    cout << "   &n=" << &n << endl; 
    cout << "}" << endl;
    n++;
}

void Reference(int &n)
{
    cout << "Reference(int &n)" << endl;
    cout << "{" << endl;
    cout << "   n=" << n << "  &n=" << &n << endl;
    cout << "}" << endl;
    n++;
}

void Pointer(int *n)
{

    cout << "Pointer(int *n)" << endl;
    cout << "{" << endl;
    cout << "   n=" << n << "  &n=" << &n << endl;
    (*n)++;

    int b = 20;
    cout << "   b=" << b << "  n = &b" << endl;

    n = &b;
    cout << "   n=" << n << "  &n=" << &n << endl;
    (*n)++;
    cout << "}" << endl;
}

int main()
{
    int n = 10;
    cout << "n = " << 10 << "  &n=" << &n << endl<< endl;


    Value(n);
    cout << "after Value() n=" << n << endl << endl;

    Reference(n);
    cout << "after Reference() n=" << n << endl << endl;

    Pointer(&n);
    cout << "after Pointer() n=" << n << endl << endl ;

    system("pause");
    return true;
}

è¿éåå¾çæè¿°

值传递时函数操作的并不是实参本身,形参和实参是相互独立的,所以对形参进行操作并不会改变实参的值。

引用传递操作地址是实参地址 ,形参相当于实参的一个别名,对它的操作就是对实参的操作。

指针传递时,可以通过指针操作实参,同样可以改变实参的值。

指针传递参数本质上是值传递的方式,它所传递的是一个地址值。值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值。 
在值传递过程中,被调函数的形式参数作为被调函数的局部变量,即在栈中开辟了内存空间以存放由主调函数放进来的实参的值,前面说过,值传递是单向传递(实参->形参),赋值完毕后实参就和形参没有任何联系。那指针传递是怎么通过这个局部变量访问实参的呢,当然是通过局部变量中存储的地址。 


一、值传递

值传递,这与C函数的性质有关。C函数的所有参数均以“传值调用”方式进行传递,这意味着函数值将获得参数值的一份拷贝,函数可以放心修改这个拷贝值,而不必担心会修改调用程序实际传给他的参数。 
我们先来看实现函数swap1:

执行结果如下: 
1

实参a的地址为:0018FF44,实参b的地址为0018FF40

2

栈区(stack)— 程序运行时由编译器自动分配,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。程序结束时由编译器自动释放。因此,参数a,b是存放在栈区的。在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。因此,我们会看到a,b的地址是呈减少的趋势。

因此,按照“值传递”的思想,形参是实参的拷贝,程序会开辟一块新的栈区为形参。它们进行交换操作是在这块新的栈区里面,并不影响实参的那一块内存。

执行完swap1函数,形参的内存中a,b的值发生了变化,但并不影响实参的的值。

在函数调用时,参数是从右到左读的,所以b的地址比a的地址高 
3

二、指针传递

我们来看实现函数swap2:

运行结果: 
4

因此我们可以看到,形参的值实际是实参的地址,因为c语言是值传递,main函数中传入的是&a,&b即a,b的地址,所以形参中存储的也是a和b的地址。 
5 
然后执行:

*a是什么意思?*a是地址为a的内存中所存储的函数值。所以上面三条语句的意思就是地址为a的内存中所存储的函数值与地址为b的内存中所存储的函数值进行交换。如下图:

6

因此,他修改的是实参的内容。执行完后实参的内容应该是这样的:

6

所以,这个时候a的值为6,b的值为5。

三、引用传递

我们来看实现函数swap3:

执行结果截图: 
7

发布了22 篇原创文章 · 获赞 6 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/baidu_18891025/article/details/81737600