关于址传递的思考

值传递:
如果参数类型是八种基本类型,那么传过来的就是这个参数的一个副本,也就是这个原始参数的值,这个跟之前所谈的传值是一样的。如果在函数中改变了副本的值不会改变原始的值.
址传递
如果参数类型是引用类型,那么传过来的就是这个引用参数的副本,这个副本存放的是参数的地址。
如果在函数中没有改变这个副本的地址,而是改变了地址中的值,那么在函数内的改变会影响到传入的参数。
如果在函数中改变了副本的地址,如new一个,那么副本就指向了一个新的地址,等函数结束,副本的生命周期也就结束了。而传入的参数还是指向原来的地址,所以不会改变参数的值。

看一段代码:

public class T180806 {
    public static void main(String[] args) {
        MyNum c1 = new MyNum(2);
        MyNum c = new MyNum(1);
        Test(c,c1);
        System.out.println("c = "+c);
        System.out.println("c1 = "+c1);
    }
    static void Test(MyNum t, MyNum a1) {
        t = a1;
        t.setA(3);
    }

}

public class MyNum {
    public int a;
    public MyNum(int b) {
        this.a = b;
    }
    public int getA() {
        return a;
    }

    public void setA(int a) {
        this.a = a;
    }

    @Override
    public String toString() {
        return "MyNum [a=" + a + "]";
    }
}

运行结果:

c = MyNum [a=1]
c1 = MyNum [a=3]

分析:
在Test1中c、c1的值分别赋值给两个形参(他俩的值是俩地址,c指向new MyNum(1),c2指向new MyNum(2),这里我简称区域1和区域2)。
当t= a1时,t指向指向区域2,当执行t.setA(3)时,区域2的值被修改为3。

当Test的生命周期结束时,两个形参t和a1所在栈创建的空间也被销毁。
但是他们被销毁前所指向的堆内的区域,依旧存在,他们对其做的修改,依旧有效。
当输出c和c1时,c和c1依旧分别指向区域1和区域2。输出也就是 1和3

<think>我们正在讨论C/C++中的参数传递方式。用户希望理解值传递、指针传递(即地传递)和引用传递之间的区别,以及如何在代码中正确使用它们。根据用户提供的引用和之前的上下文,我将详细解释这三种传递方式。###1. **值传递(Passby Value)**- **机制**:将实参的值复制一份给形参。函数内操作的是形参(实参的副本),因此对形参的任何修改不会影响实参。- **C语言示例**:```cvoid modify(int n) {n+=10;//修改的是副本}intmain(){int value=5;modify(value);printf("Value= %d",value);//输出5(未改变)}``` -**特点**:-安全:函数内部无法修改原始数据。-开销:对于大型结构体或对象,复制成本高。###2.**指针传递 (Pass byPointer)/地传递** -**机制**:将实参的地传递给形参(指针变量)。函数内通过解引用操作符`*`访问和修改原始数据。 -**C语言示例**:```cvoidmodify(int*p) {*p +=10;//通过指针修改原始数据}intmain(){int value=5;modify(&value);//传递printf("Value =%d", value); //输出15}```- **特点**:-可修改原始数据。-显式使用`&`和`*`操作符,代码意图清晰。-需注意空指针和野指针问题。 ###3. **引用传递(Passby Reference)**- **机制**(仅C++支持):形参是实参的别名,操作形参即直接操作实参。语法上无需解引用。- **C++示例**:```cppvoid modify(int &n){//引用参数n +=10;//直接修改原始数据}int main() {intvalue =5;modify(value);//调用方式同值传递cout<< "Value =" <<value;//输出15}```- **特点**:-语法简洁,无需指针操作符。-底层实现类似指针(传递),但安全性更高(无空引用)。-是C++特有的机制,C语言不支持。---###关键区别总结| **特性**|**值传递**| **指针传递**| **引用传递**| |------------------------|------------------|--------------------|--------------------| |**传递内容**|值的副本|地|别名(底层是地)| |**修改原始数据**|不可|可(需解引用)|可(直接操作)| |**空值风险**|无|有(空指针)|无(引用必绑定)| |**语法复杂度**|简单|中等(需`*`和`&`) |简单| |**语言支持**|C/C++| C/C++|仅C++| |**大型对象传递开销**|高(复制)|低(传地)|低(传地)|| **函数内修改意图**|副本独立|显式修改|隐式修改|--- ###内存模型图解```mermaidgraphLRsubgraph值传递A[main:value=5]-->|复制值| B[modify: n=5]B -->|修改n=15|C[副本销毁]A -->|输出| D[value仍为5]endsubgraph指针传递E[main:value=5<br>地0x1000] -->|传递|F[modify: p=0x1000]F-->|*p+=10|G[修改0x1000处值为15]E-->|输出|H[value=15]endsubgraph引用传递I[main: value=5<br>地0x2000] -->|绑定别名|J[modify: n是0x2000的引用]J -->|n+=10|K[修改0x2000处值为15]I -->|输出| L[value=15]end``` ---###使用建议1.**C语言**:-需修改原始数据→ **指针传递**-只读访问→值传递(小型数据)或`const`指针(大型数据)2.**C++**:-需修改原始数据→ **引用传递**(更安全简洁)-只读访问 →`const`引用(避免复制开销)-可选指针传递(需显式操作指针的场景) >注意:引用传递是C++对指针传递的封装和增强,避免了指针的语法冗余和空指针风险[^3]。--- ###悬空引用问题引用传递虽安全,但仍需注意:```cppint&badRef() {intlocal =10;return local; //返回局部变量的引用!}int main() {int&r= badRef();// r成为悬空引用cout<< r;//未定义行为(可能崩溃) }``` **解决方案**:确保引用绑定到生命周期足够长的对象。 ---###相关问题1.为什么C语言不支持引用传递?2.在C++中,何时应优先使用指针传递而非引用传递?3.如何理解“引用是常量指针”(`int&⇔ int* const`)?4.传递数组时三种方式有何差异?[^1]:值传递和地传递区分,谭浩强《C语言程序设计》[^2]:C/C++函数参数传递的三种方式[^3]:引用传递与指针传递的本质差异[^4]:指针传递中的值拷贝特性</think>### 值传递、指针传递传递)和引用传递的区别详解 #### 1. **值传递 (Pass by Value)** - **机制**:将实参的值**复制**一份给形参 - **特点**: - 函数内操作的是实参的副本 - 不会修改原始变量 - **内存模型**: ```mermaid graph LR main[主函数变量] -->|复制值| func[函数形参] func --修改副本--> 新值 main --保持不变--> 原值 ``` - **C语言示例**: ```c void modify(int n) { // 值传递 n += 10; // 修改副本 } int main() { int value = 5; modify(value); // 传递值 printf("%d", value); // 输出5(未改变) } ``` #### 2. **指针传递/传递 (Pass by Pointer)** - **机制**:传递变量的**内存地** - **特点**: - 函数内通过解引用操作符`*`修改原始数据 - 形参指针与实参指针是**不同**的指针变量(值相同但地不同) - **内存模型**: ```mermaid graph LR main[主函数变量] -->|地| ptr1[指针变量1] func[函数形参指针] -->|同地| ptr2[指针变量2] ptr2 --*操作--> 修改内存 ptr1 --访问--> 修改后的值 ``` - **C语言示例**: ```c void modify(int* p) { // 指针传递 *p += 10; // 解引用修改原始数据 } int main() { int value = 5; modify(&value); // 传递 printf("%d", value); // 输出15(已修改) } ``` - **关键特性**: - 能修改原始数据,但形参指针本身是副本[^4] - 需显式使用`&`和`*`操作符 #### 3. **引用传递 (Pass by Reference)** - **机制**(仅C++支持):形参是实参的**别名** - **特点**: - 语法上像值传递,行为上像指针传递 - 形参与实参共享**同一内存地** - **内存模型**: ```mermaid graph LR main[主函数变量] -->|绑定| ref[引用变量] ref --直接操作--> 内存块 main --直接访问--> 同一内存块 ``` - **C++示例**: ```cpp void modify(int& n) { // 引用传递 n += 10; // 直接修改原始数据 } int main() { int value = 5; modify(value); // 传递引用 cout << value; // 输出15(已修改) } ``` - **关键特性**: - 无解引用语法,直接操作原始变量[^3] - 底层实现类似指针,但语法更安全(无空引用) --- ### 三种方式对比表 | 特性 | 值传递 | 指针传递 | 引用传递 | |--------------------|-------------|------------------|------------------| | **传递内容** | 值副本 | 内存地 | 别名绑定 | | **修改原始数据** | 不可 | 可(需解引用) | 可(直接操作) | | **语法复杂度** | ★☆☆ (简单) | ★★☆ (中等) | ★☆☆ (简单) | | **空值风险** | 无 | 有空指针风险 | 无空引用 | | **内存开销** | 复制整个对象 | 固定大小(地) | 固定大小(地) | | **语言支持** | C/C++ | C/C++ | 仅C++ | | **典型操作符** | - | `&`, `*` | `&`(声明时) | --- ### 使用场景建议 1. **值传递**: - 基本数据类型(int, float等) - 不需要修改原始数据的场景 - 函数内操作不影响外部的需求 2. **指针传递**: - 需要修改原始数据 - C语言中唯一的选择 - 需要明确传递的场景(如动态内存管理) 3. **引用传递**: - C++中需要修改原始数据 - 大型对象避免复制开销 - 需要简洁语法的场景(如操作符重载) > **关键区别总结**:指针传递中形参指针是实参指针的**副本**(两者地不同但指向相同内存),而引用传递中形参和实参是**同一内存的别名**(无副本产生)[^3][^4]。 --- ### 相关问题 1. 为什么C语言不支持引用传递?其设计哲学是什么? 2. 在函数返回局部变量的地时,指针传递和引用传递分别有什么风险? 3. 如何用指针传递模拟引用传递的行为? 4. `const`引用在C++中有哪些特殊应用场景? 5. 在面向对象编程中,三种参数传递方式对多态性的支持有何差异? [^1]: 值传递机制详解,谭浩强《C语言程序设计》 [^2]: 三种参数传递方式的本质区别 [^3]: 引用传递与指针传递的内存差异 [^4]: 指针传递中的值拷贝特性
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喜鹊先生Richard

随缘~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值