C++ 关于 调用函数时值传递和引用的理解

适合初学者。

函数参数传递机制

堆栈存储区是主调函数(过程)和被调用函数(过程)在调用发生时进行通信的主要区域。
基本的参数传递机制有两种:值传递和引用传递。

值传递:

被调用的函数的形式参数作为被调函数局部变量处理,即在堆栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本,不会影响主调函数实参变量的值。

那么为什么课本上说指针传递可以改变某些数的值呢?

指针传递的是地址,即一个指针本身是一个地址,传递给函数的是一个地址副本,但因为地址与地址副本指向的是内存中的同一个地方,所以可以修改指针指向数据的值。

但是如果要更改指针,也就是更改指针指向的地址,这样就不行了,要用指向指针的指针才可以。

void swap1(int *x, int *y)
{
    int temp;
    cout<<x<<endl;
    cout<<y<<endl;
    temp = *x;
    *x = *y;
    *y = temp;
}

int main()
{
    int a = 1,b=2;
    int *a1=&a;
    int *b1=&b;
    cout<<a<<endl;
    cout<<b<<endl;
    swap1(a1,b1);
    cout<<a<<endl;
    cout<<b<<endl;
}

引用传递

引用传递和指针有相似之处,本质上都是传递的地址,但是指针可以直接传过去,但是引用传入的是地址偏移量,系统通过地址偏移量计算到地址,来做一些更改。

void  swap2(int &x, int &y)
{
    cout<<"x="<<x<<endl;
    cout<<"y="<<y<<endl;
    int temp;
    temp = x;
    x = y;
    y = temp;

}
int main()
{
    int a = 1, b = 2;
    swap2(a,b);
    cout<<"a="<<a<<endl;
    cout<<"b="<<b<<endl;
}

但通过一个测试发现,在swap2中输出x,输出的并不是地址偏移量,而是x本身的值,只是因为被调函数对形参的任何操作都被处理成间接寻址,即通过堆栈中存放的地址访问主调函数中的实参变量,我们对x做操作的时候x,系统帮我们间接寻址了,所以我们访问到的不是地址而是变量。

两重指针的应用

void change(int **t)
{
    //t是a指针的地址
    //*t是a的地址
    //**t是a
    cout<<t<<endl;
    cout<<*t<<endl;
    cout<<**t<<endl;
}

int main()
{
    int a=3;
    int *b=&a;
    change(&b);
    cout<<b<<endl;
    return 0;
}

运行结果

0x69fef8
0x69fefc
3
0x69fefc

我们能用引用更改指针的地址

  int m=10;
  int*n=&m;
  void swap(int*&a)   
  {     
     a=n;   //a地址被n替换
  } 

结束!

——————————————————————————
还有一个小知识点,

int main()
{
    int a = 1;
    int &b=a;
    cout<<&a<<endl;
    cout<<&b<<endl;
}

这里输出的a的地址与b的地址是一样的,b只相当于a的一个别名而已,也可以说一个地址有两个名字。

参考博客:
http://blog.youkuaiyun.com/xiven/article/details/4229599

http://www.cnblogs.com/zhaobing/archive/2013/03/18/2966280.html

### Java 中函数调用时值传递的工作方式 在 Java 编程语言中,所有的参数传递都是通过值传递实现的。这意味着无论何时调用方法并提供参数,都会创建这些参数的一个副本,并将此副本用于方法内部的操作。 对于基本数据类型的参数而言,情况较为直观。由于整数、浮点数等基础类型的数据量较小,因此直接复制其具体的数值即可完成传递过程[^1]: ```java public class ValuePassingExample { public static void changeValue(int num) { num = 99; } public static void main(String[] args) { int originalNum = 5; changeValue(originalNum); System.out.println("After method call, the value is " + originalNum); // 输出结果为5 } } ``` 当涉及到对象作为参数的情况时,虽然表面上看起来像是引用传递——因为可以在被调用的方法内更改对象属性从而影响原始对象的行为;但实际上,这里依然是基于值传递机制工作的。此时,“值”指的是指向堆内存中某个特定位置的对象引用(即指针)。也就是说,真正发生的事情是:原对象引用所指向的位置信息被复制了一份新的引用变量来表示它,而并非整个对象结构体本身进行了转移或共享[^3]。 为了更清晰地展示这一点,可以考虑下面的例子: ```java class Person { String name; public Person(String name) { this.name = name; } } public class ReferencePassingExample { public static void changeName(Person person) { person.name = "New Name"; } public static void main(String[] args) { Person p = new Person("Old Name"); changeName(p); System.out.println("The final name of the object is: " + p.name); // 输出结果为 New Name } } ``` 在这个例子中,`changeName()` 方法接收到了 `p` 的一个副本,但这只是对同一个 `Person` 实例的不同引用而已。因此,在该方法体内所做的任何针对 `person` 变量对应对象成员字段 (`name`) 的变更都将反映回原来的实例上。然而这并不意味着这是真正的引用传递,因为在 C++ 或其他支持严格意义上的引用语义的语言里,引用一旦绑定就不能再重新赋值给另一个不同的实体,而在上述代码片段中是可以让局部变量 `person` 指向一个新的 `Person` 对象而不影响外部传入的那个对象的[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值