内存(传值、传址、传引用)

本文通过三个示例详细解释了C++中传值、传址和传引用的区别,包括它们如何影响函数参数及内存中的数据。通过直观的堆栈图展示了不同传参方式下内存的变化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


前言:


          最近对内存产生了兴趣、全是因为马士兵老师的一句Master key、马上要考二级了、大题构造函数比较多、形参有 int & x  这么写的、也有int *x 这么写的、还有普通 int x这么写的、我的乖乖这都是传的什么?


           int x 是 传值、int *x  是传址、 int & x是传引用、那这三者传参数都有什么区别呢?


下面就用三个例子讲解


          声明:下面堆栈的图其实是不正确的、八个基本类型(byte、short、int、long、char、float、double、boolean)都是在栈里面的、而下面的int型我把名字看做栈里面、里面的数值看做是堆里面的、只是为了大家明白传值、址、引用、的区别。


<span style="font-size:18px;">// C_TEST.cpp : Defines the entry point for the console application.
//
//
#include "stdafx.h"
#include "iostream"
using namespace std;//我是在VS2008里面作的调试,这里需要导入命名空间STD
</span>




传值


<span style="font-size:18px;">//传值
	void swap1(int x,int y)
	{
		X = 3
		Y = 4
		cout<<"     传值函数输出:    "<<x<<"     "<<y<<endl;
		
		
	}
	void main()//入口点
	{
	 int a(1);
	 int b(2);
	swap1(a,b);
	cout<<"     外界值:      "<<a<<"     "<<b<<endl;
	
	}
	
//输出:
	//传值函数输出:3 4
	//外界值: 1 2
</span>



堆栈图(执行swap1前、执行swap1后)




           

          是把实参的值赋值给行参   、那么对行参的修改,不会影响实参的值   。


          简单的说就是、栈里面的地址、堆里面的对象都不是一个、比如我有首《chenchen绝唱》这首歌、我拷给了我的好同桌许小乖、她觉得特难听、立马就删了、她删了歌、我这还有、互不影响、还有一点要说明的就是、栈里存放着指向对象的地址、所以对象复制出来是一样的、但是堆里的地址不一样、所以ab栈的地址与xy栈的地址不一样、就好似我的歌放在我的硬盘里、考给同桌的歌放在她的硬盘里、物理地址不一样。





传址


这里把x、y做了交换、因为是传址、所以更改了a 、b指向堆里面的对象。


//传址
	void swap2(int *x,int *y) //传址调用
	{
	 //把主函数里数据的地址传了过来
	 //这里改变了数据的地址,在主函数里打印出a,b的时候,当然就发生了交换!
	   int temp;
	   temp = *x;
	   *x = *y;
	   *y = temp;
	   cout<<"     传址函数内:    "<<x<<"     "<<y<<endl;
	}
	void main()//入口点
	{
	 int a(1);
	 int b(2);
	swap2(&a,&b);
	cout<<"     外界值:      "<<a<<"     "<<b<<endl;
	
	}
//输出:
	//传址函数输出:0016FE04 0016FDF8
	//外界值: 2 1


这里打印了x y 是 内存 地址、交换操作却是对堆里对象的操作。


堆栈图(执行swap2前、执行swap2后)




       

       是传值的一种特殊方式,只是他传递的是地址,不是普通的如int   


          
那么传地址以后,实参和行参都指向同一个对象   


          对x、y的操作、互换、其实就是对a、b值的互换、因为他们都指向同一个对象、打个比方、有两张一模一样的藏宝图、你一张、我一张、但是宝藏只有一个、我找到宝藏、拿走了、你再过去拿宝藏就没有了、所以传址只是把地址传过来、用的对象还是那个对象、所以x y值的互换就是 对象 1 和2 值的互换、但是ab的指向的地址没变、堆里两个对象的值却互换了。





传引用


<span style="font-size:18px;">//引用
void swap3(int &x,int &y)//传引用
{
 //加了&之后,用地址引用了主函数里面的数据值,说明x,y 的地址是a,b的地址~~,因而主函数里面的a,b发生交换~~
   int temp;
   temp = x;
   x = y;
   y = temp;
   cout<<"     换址函数内:    "<<x<<"     "<<y<<endl;
}

void main()//入口点
{
 int a(1);
 int b(2);
 swap3(a,b);
cout<<"     外界值:      "<<a<<"     "<<b<<endl;

}

//输出:
	//传址函数输出:21
	//外界值: 2 1
</span>



堆栈图(执行swap3前、执行swap3后)





          这里的图有可能不太对、但是我能这么理解了、打个比方吧、一人拿着一张藏宝图叫我去找宝藏、藏宝图给了我、我去把宝藏拿给他、上图栈里的x y应该是指向a b 或者是a b的别名。


-----------------------------------------------------------------------------------

函数调用角度SEE  
    
  
传值:

    
  
传值:
   
            
函数参数压栈的是参数的副本。
   
            
任何的修改是在副本上作用,没有作用在原来的变量上。
   
    
  
传指针:
   
            
压栈的是指针变量的副本。
   
            
当你对指针解指针操作时,其值是指向原来的那个变量,所以对原来变量操作。
   
    
  
传引用:
   
            
压栈的是引用的副本。由于引用是指向某个变量的,对引用的操作其实就是对他指向的变量的操作。(作用          和传指针一样,只是引用少了解指针的草纸)
  

-----------------------------------------------------------------------------------


总结:

         这两天学了内存发现挺有意思的、说是换真还是一头雾水、不是特别清楚、但是感觉真的对分析程序很有帮助、基础知识嘛、要好好学。




参考文章

          http://blog.youkuaiyun.com/juliababy/article/details/2837646

         http://blog.youkuaiyun.com/aristolto/article/details/7262738



——————————————— 困-困 ———————————————


——————————chenchen——————————


<think>好的,我现在需要回答用户关于C语言中引用的区别及使用场景的问题。首先,我需要明确用户的问题点,用户可能已经了解了一些基本概念,但可能对具体区别和应用场景不太清楚。根据提供的引用资料,特别是引用[1]、[2]、[3]和[4],我需要将这些信息整合成一个清晰的回答。 首先,调用和调用(即引用的一种实现方式)的基本区别。引用[1]提到调用递的是变量地址,允许函数修改原始变量。而调用递的是的副本,不会影响原变量。引用[3]中的swap函数示例展示了调用无法交换变量的问题,而引用[2]的示例则用指针实现了调用,成功交换了。 接下来,需要区分C语言中的引用是否准确。根据我的知识,C语言中没有真正的引用,而是通过指针来实现类似效果,而C++才有引用类型。但用户可能将调用理解为引用,所以需要澄清这一点,避免混淆。引用[4]提到C++中的引用,但用户问题集中在C语言,所以主要讨论指针实现的。 然后,使用场景方面,引用[2]指出地址用于修改外部变量和递大结构,避免复制开销。需要分点说明这些场景,并举例,如交换变量、数组操作、结构体递等。 另外,需要比较两者的优缺点。安全但效率低,高效但有风险。同时,可以提到const指针来增加安全性。 最后,生成相关问题,可能涉及指针的其他应用、参数递最佳实践、与C++引用的对比等。 现在需要组织这些信息,确保符合用户要求的结构:分点回答,使用中文,正确使用LaTeX,添加引用标识。同时检查是否有遗漏或错误,比如C语言中的引用问题是否正确处理。</think>### C语言中的区别及使用场景 #### 一、核心区别 1. **调用** - **定义**:函数接收参数的**副本**,与原变量完全独立。 - **特点**:函数内对参数的修改**不会影响外部变量**。 - **示例**: ```c void modify(int x) { x = 10; } // 仅修改副本 int main() { int a = 5; modify(a); printf("%d", a); // 输出 5 [^3] } ``` 2. **调用**(通过指针实现) - **定义**:函数接收变量的**内存地址**,可直接操作原始数据。 - **特点**:函数内通过解引用(`*`)能**修改外部变量**的。 - **示例**: ```c void swap(int *a, int *b) { // 接收地址 int temp = *a; *a = *b; *b = temp; } int main() { int x = 5, y = 10; swap(&x, &y); // 地址 printf("x=%d, y=%d", x, y); // 输出 x=10, y=5 [^2] } ``` --- #### 二、使用场景对比 | **场景** | **调用** | **调用** | |------------------------|---------------------------------------|------------------------------------------| | **修改变量需求** | 不需要修改外部变量(如计算数学函数) | 需要修改外部变量(如交换、更新状态) | | **数据大小** | 小型数据(int、char等) | 大型数据(数组、结构体),避免复制开销[^2] | | **安全性** | 高(隔离原始数据) | 低(需谨慎操作,防止意外修改) | --- #### 三、典型应用示例 1. **修改外部变量** - **场景**:交换变量、更新结构体字段。 - **代码**: ```c void reset(int *arr, int size) { for(int i=0; i<size; i++) arr[i] = 0; // 直接修改数组元素 } ``` 2. **高效递数据** - **场景**:递包含1000个元素的结构体时,仅复制指针(4/8字节),需复制整个结构体(可能数千字节)。 3. **返回多个** - **场景**:通过指针参数返回计算结果(如同时返回商和余数)。 - **代码**: ```c void divide(int a, int b, int *quotient, int *remainder) { *quotient = a / b; *remainder = a % b; } ``` --- #### 四、注意事项 1. **的安全性** - 使用`const`限定符防止误修改(如`const int *ptr`)。 2. **空指针检查** - 递指针前应验证其有效性,避免解引用空指针导致崩溃。 ---
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值