传值调用 与传地址调用(传引用)

本文深入探讨了C++中三种参数传递方式:值传递、引用传递和指针传递的细节及其实现效果,通过具体代码示例展示了每种方式如何影响函数内部变量,并解释了背后的原因。

#include <iostream>

using namespace std ; 

void Swap(int x, int y) ;

int main(void)

{

            int a = 1 ;

            int b = 2 ;

 

            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 temp = x ;

            x = y ;

            y = temp ;

}

 

输出结果:

a = 1, b = 2

a = 1, b = 2

原因:Swap(int x, int y)函数采用值传递的方式,传入的实参实际上是a和b的副本而非其本身,所以对副本的改变并不会反应到a和b本身上。这个例子很简单,但是大一最开始学的时候,压根就不理解,因为那时候对内存的原理和结构不熟悉!!!

 

二:引用传递

void Swap(int &x, int &y)

{

            int temp = x ;

            x = y ;

            y = temp ;

}

 

输出结果:

a = 1, b = 2

a = 2, b = 1

原因:Swap(int x, int y)函数采用引用传递的方式,传入的实参实际上是a和b的引用,对引用的改变会直接反应到a和b本身上。引用是C++引进的语法,是一个很有用的工具吧,实质上就是包装了指针,简化程序猿的负担,理解了指针才能理解引用,我们当然不能只停留在死记硬背上面,当然是要自己画出数据在内存中的存储方式。

 

三:指针传递

1.  改变指针本身

void Swap(int *x, int *y)

{

            int *temp = x ;

            x = y ;

            y = temp ;

}

 

调用方法:Swap(&a, &b) ;

 

输出结果:

a = 1, b = 2

a = 1, b = 2  //这里是不是让你大吃一惊,反正我当时是惊呆了,这个当时还就是今年的4月时候,不过当时真没有写过这样的指针形式,也没有遇到这样的情形,这个例子对加深函数的参数传递是很有帮助的,也就是说函数传递参数都是传递的实参的副本,即使是传递的指针副本,这个例子里面我们没有对这个副本指针进行解除引用操作(*)也即间接引用,所以我们是访问不到实参变量的,这里进行的赋值也只是对指针副本进行的赋值.  当时真的没有想这么多哎,只是傻傻的以为指针很好用,能够操作内存,好酷炫,还以为是很神秘的技术,原来也是传递的一个副本.只是C语言提供了对它操作内存的能力。用*操作就可以直接访问实参变量...要用心(*)啊!!!不得不赞C语言.

原因:Swap(int x, int y)函数采用指针传递的方式,传入的实参实际上是a和b的指针的副本,而且改变的是副本本身而非其间接引用,所以不会影响的指针所指向的值,即a和b本身上。

 

2.  改变指针的间接引用

 

void Swap(int *x, int *y)

{

            int temp = *x ;

            *x = *y ;

            *y = temp ;

}

 

调用方法:Swap(&a, &b) ;

 

输出结果:

a = 1, b = 2

a = 2, b = 1

原因:Swap(int x, int y)函数采用指针传递的方式,传入的实参虽然也是a和b的指针的副本,但是改变的是副本的间接引用,无论是指针本身还是其副本,都指向相同的值,所以这个改变会反应到a和b本身

   总之,如果想在被调用函数中改变哪个变量的值就需要把那个变量的地址传给被调用函数,这样在被调用函数中通过地址就可以访问和修改这个变量。传值的时候会对参数进行拷贝,然后传给被调用函数,而传地址只是对地址进行一份拷贝,然后赋给形参,这样在C++中如果传递一个比较大的对象时效率就有所区别了。 对于简单类型的变量来说传值和传地址在根本上是没有区别的,都是传递一个数给被调用函数,地址本身就是一个变量,地址变量大小与地址总线有关,常用的是32位地址总线,也就是说地址变量大小为4Bytes(32bit),而怎样去解释和使用这个数是我们事先约定好的。约定好的呀!! 计算机就为我们所用噜,想去哪就去哪...致指针...

转载于:https://www.cnblogs.com/QingCHOW/p/4588483.html

<think>首先,用户的问题是关于理解引用调用(call byreference)和值调用(callby value)的区别及其在编程中的应用。用户提供了几个引用,我需要参考这些引用,但最终回答要基于用户的问题。关键点: -用户要求回答结构清晰,帮助用户逐步解决问题。-回答要真实可靠。-在回答中引用的段落末尾自然地添加引用标识,如[^1]。-使用中文回答。 -所有行内数学表达式用$...$格式,独立公式用$$...$$格式。 -生成相关问题。 参考引用:-[^1]:解释了值调用调用引用),包括定义、区别、指针地址递、Java中的模拟、应用场景、风险和注意事项。- [^2]:讨论了值、指针和引用,强调引用时形参和实参地址相同。 -[^3]:在C++中,使用引用符号(&)表示引用,修改形参影响实参。 -[^4]:在C++中,值、引用传地址的区别,包括指针和引用的功能。 -[^5]:在C语言中,值调用中形参销毁不影响实参。 我的回答需要覆盖:1.定义值调用引用调用。 2.解释它们的区别。3.各自的特点(优点和缺点)。4.在编程中的应用场景。 5.风险和注意事项。 6.自然地引用提供的引用。 回答结构:1.**引言**:简要介绍主题。 2. **定义**:分别解释值调用引用调用。 3. **区别**:比较两者,包括参数递方式、对实参的影响等。 4. **特点**:讨论各自的优点和缺点。 5. **应用场景**:给出实际编程中的例子。6.**风险和注意事项**:提醒潜在问题。 7. **小结**:总结关键点。 8. **相关问题**:生成相关问题。 确保语言清晰、中文流畅。 添加引用:在相关段落末尾自然地添加引用标识。例如,当提到某个概念时,参考引用。生成相关问题:在最后添加相关问题。现在,构建回答。</think>### 引用调用值调用的区别及其应用 在编程中,函数参数的递方式直接影响程序的行为和性能。值调用(Call by Value)和引用调用(Call by Reference)是两种核心机制,理解它们的区别对于编写高效、可靠的代码至关重要。下面我将逐步解析它们的定义、区别、特点、应用场景及相关风险。 #### 1. **定义** - **值调用(Call by Value)**:函数调用时,实参的值被复制一份递给形参。形参在函数内部是独立的局部变量,修改形参不会影响原始实参的值。例如,在C语言中,基本数据类型(如`int`、`float`)通常采用值方式。引用[^5]指出,形参只在函数作用域内有效,函数结束后自动销毁,因此实参不受影响。 - **引用调用(Call by Reference)**:函数调用时,实参的地址(或引用)被递给形参,形参和实参共享相同的内存位置。因此,在函数内部修改形参会直接改变实参的值。在C++中,使用引用符号`&`(如`int &x`)表示引用;在Java中,对象参数虽为值递,但通过引用模拟类似行为。引用[^3]强调,引用时“形参和实参共享地址”,修改形参即修改实参。 #### 2. **主要区别** 两者的核心区别在于参数递机制和对实参的影响: | 方面 | 值调用 | 引用调用 | |------|----------|------------| | **参数递方式** | 实参的值被复制到形参 | 实参的地址引用递给形参 | | **内存使用** | 形参有独立内存空间,增加开销 | 形参和实参共享内存,减少开销 | | **对实参的影响** | 修改形参不影响实参 | 修改形参直接改变实参 | | **性能** | 适用于小型数据,效率较高 | 适用于大型数据(如数组、对象),避免复制开销 | | **语法示例** | C语言:`swap(int a, int b)` | C++:`swap(int &x, int &y)` | 关键点:引用时,形参地址实参地址相同,属于同一存储空间;而值或指针(如C语言)时,形参地址独立[^2]。数学上,这类似于变量绑定:值对应值复制$v_{\text{形参}} = v_{\text{实参}}$,引用对应地址共享$p_{\text{形参}} = p_{\text{实参}}$。 #### 3. **各自特点** - **值调用的特点**: - **优点**:简单安全,避免意外修改实参;适用于小型数据或不需要修改实参的场景。 - **缺点**:复制大对象(如结构体或数组)时性能低下,增加内存和时间开销。引用[^1]提到,值调用“在函数完成后自动销毁”,不改变原数据。 - **引用调用的特点**: - **优点**:高效,减少复制开销;直接修改实参,适合需要“副作用”的操作(如交换变量值)。 - **缺点**:风险较高,可能意外修改实参导致逻辑错误;需谨慎管理内存。引用[^4]解释,引用“提供指针的功能但更安全”,但需注意引用和指针的区别。 #### 4. **应用场景** - **值调用适用场景**: - 小型数据递:如基本类型(`int`, `char`),其中复制开销可忽略。 - 只读操作:函数不需要修改实参时,例如计算数学函数$f(x) = x^2$。 - 安全关键代码:避免副作用,如金融计算或并发编程。 - **引用调用适用场景**: - 大型数据结构:如数组、对象或类,避免复制开销。例如,在C++中排序算法使用引用递大数组。 - 需要修改实参:如交换两个变量(`swap`函数)或更新对象状态。 - 资源高效管理:在Java中,对象参数通过引用模拟,实现数据共享[^1]。 实际代码示例(C++): ```cpp // 值调用:交换失败,因为形参修改不影响实参 void swapByValue(int a, int b) { int temp = a; a = b; b = temp; // 修改局部变量 } // 引用调用:交换成功,形参和实参共享地址 void swapByRef(int &x, int &y) { int temp = x; x = y; y = temp; // 直接修改实参 } ``` 在以上代码中,`swapByValue`无法改变实参值,而`swapByRef`能正确交换,体现了引用递的优势[^3]。 #### 5. **风险和注意事项** - **值调用风险**:复制大对象可能导致性能瓶颈;在递归或高频调用中,内存消耗累积。 - **引用调用风险**:意外修改实参引发bug(如数据污染);在指针递中,可能产生悬空引用或内存泄漏。引用[^1]警告,调用需“注意指针有效性和作用域”。 - **最佳实践**:在C++中,优先使用`const`引用(如`const int &x`)实现只读递;在Java中,对象递本质是值递(引用副本),但可通过方法修改对象状态[^4]。 #### 6. **小结** 值调用通过复制值实现安全隔离,适合小型数据;引用调用通过共享地址提高效率,适合大型数据或需修改实参的场景。选择哪种方式取决于数据大小、性能需求和安全性。理解指针、地址引用的底层机制(如引用[^2]所述)是掌握高级编程的关键。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值