指针和地址的区别

本文由作者丫丫通过实例代码分析了指针和地址在二叉树建立过程中的不同之处。文章指出,传递指针时,指针所指内容不会改变,而传递地址则会导致该地址的内容发生变化。

/*
作者:丫丫
功能:测试传递指针和传递地址不一样(以二叉树的建立分析)
结论:传递指针指针所指的不容不会被改变,而传递地址则该地址的内容会被改变
日期:2014年12月3日
*/

#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#define STACK_SIZE 50
//定义二叉节点
typedef struct Node
{
    char data;
    struct Node * LChild;
    struct Node * RChild;
}BiTNode, *BiTree;
//创建一棵二叉树(传递地址)不需要返回值

void CreatBiTree(BiTree * T)
{
    char ch;
    ch = getchar();
    if (ch == ' ')
        (*T) = NULL;
    else
    {
        (*T) = (BiTree)malloc(sizeof(BiTNode));
        (*T)->data = ch;
        CreatBiTree(&((*T)->LChild));
        CreatBiTree(&((*T)->RChild));
    }
}

//创建一棵二叉树(传递指针)需要返回值
/*
BiTree CreatBiTree(BiTree T)         //T为指针类型,传递的是指针
{
    char ch;
    ch = getchar();
    if (ch == ' ')
        T = NULL;
    else
    {
        T = (BiTree)malloc(sizeof(BiTNode));
        T->data = ch;
        T->LChild = CreatBiTree(T->LChild);
        T->RChild = CreatBiTree(T->RChild);
    }
    return T;            //返回创建的二叉树
}
*/
//先序遍历二叉树的递归算法
void PreOder(BiTree T)
{
    if (T != NULL)
    {
        printf("%c", T->data);
        PreOder(T->LChild);
        PreOder(T->RChild);
    }
}
//中序遍历二叉树的递归算法
void InOder(BiTree T)
{
    if (T != NULL)
    {
        InOder(T->LChild);
        printf("%c", T->data);
        InOder(T->RChild);
    }
}
//后序遍历二叉树的递归算法
void PostOder(BiTree T)
{
    if (T != NULL)
    {
        PostOder(T->LChild);
        PostOder(T->RChild);
        printf("%c", T->data);
    }
}
int main()
{
    BiTree T;
    printf("请按照先序遍历输入二叉树\n");
    CreatBiTree(&T);
    printf("先序遍历二叉树的递归算法:\n");
    PreOder(T);
    printf("\n中序遍历二叉树的递归算法:\n");
    InOder(T);
    printf("\n后序遍历二叉树的递归算法:\n");
    PostOder(T);
    printf("\n");
    system("pause");
    return 0;
}
<think> 首先,用户的问题是:“我想了解指针地址递的区别 请问指针地址递的区别”。根据系统级指令,我需要使用中文回答,结构清晰,逐步解决问题。 回顾系统指令: - 所有行内数学表达式用$...$格式。 - 独立公式用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识,例如[^1]。 用户引用了几个来源,我需要参考这些引用: - [^1]: 关于数组址模式,形参实参指向同一个地址,底层利用指针实现。 - [^2]: C语言中值地址递的区别地址递时函数修改指针指向的数据会影响原始变量。 - [^3]: C++中值、传地址引用的区别指针引用的区别。 - [^4]: 指针参时值地址递的区别。 - [^5]: 值消耗大是因为数据保存在栈帧中,而引用指向原数据,时间消耗小。 用户的问题核心是指针地址递的区别。在C/C++中,这两个术语经常被混淆或互换使用。我需要澄清: - "地址递"通常指的是递变量的地址,使用指针来实现。 - "指针递"可能指的是指针本身的值(值递),或者指针的引用(引用递)。 从引用中: - [^2] 区分了值地址递:值递时,函数内部修改不影响原始变量;地址递时,通过指针修改会影响原始变量。 - [^3] 讨论了指针引用的区别:引用在初始化后不能改变,指针可以;引用更安全等。 - [^5] 提到值消耗大,引用消耗小。 实际上,在C/C++中: - "地址递"通常等同于"指针递",因为地址是通过指针递的。 - 但严格来说,"指针递"可以有两种方式: - 1. 指针的值(值递):函数接收到指针的一个副本,修改副本不影响原始指针,但可以修改指针指向的数据。 - 2. 指针的引用:通过引用指针,允许修改原始指针本身。 用户可能混淆了术语。我需要解释清楚。 结构化回答: 1. **介绍概念**:简述指针地址递的含义。 2. **区别解释**:基于引用,详细说明区别。 3. **代码示例**:提供代码来展示区别。 4. **总结**:澄清常见误解。 5. **生成相关问题**:根据系统指令。 确保使用正确的LaTeX格式:行内数学表达式用$...$,如$*ptr$,独立公式用$$...$$,但可能不需要复杂公式。 回答结构: - 开头:直接回答问题。 - 主体:逐步解释。 - 结尾:总结,并生成相关问题。 参考引用: - 在回答中自然地添加引用标识,如讨论时提到引用内容加[^1]。 最终输出: - 用户可见层:回答结构清晰。 - 结束时生成相关问题。 草拟回答: 1. **定义**: - 在C/C++中,"地址递"指的是递变量的地址,通常使用指针来实现。这允许函数修改变量的值。 - "指针递"可能指的是指针变量本身。这又分为: - 值指针指针的副本。 - 引用指针指针的引用。 实际上,地址递本质上是通过指针地址。 2. **核心区别**: - 地址递:总是通过指针实现,函数接收地址,可以修改该地址指向的数据。 - 指针递:如果指值指针,则函数不能修改原始指针(但能修改数据);如果指引用指针,则可以修改原始指针。 从引用[^2]:地址递时,函数修改指针指向的值会影响原始变量。 从引用[^3]:指针引用有区别,引用更安全。 3. **示例**: - 地址递示例:类似引用[^2]。 ```c void modify(int *ptr) { *ptr = 10; // 修改地址指向的值 } int main() { int a = 5; modify(&a); // 地址递 // a 现在是 10 } ``` - 指针递(值递): ```c void changePtr(int *ptr) { int b = 20; ptr = &b; // 修改副本,不影响原始指针 } int main() { int a = 5; int *p = &a; changePtr(p); // p 仍然指向 a, 因为递的是副本 } ``` - 指针递(引用递,在C++中): ```c++ void changePtrRef(int *&ptrRef) { int b = 20; ptrRef = &b; // 修改原始指针 } int main() { int a = 5; int *p = &a; changePtrRef(p); // p 现在指向 b (但 b 是局部变量,危险) } ``` 4. **总结区别**: - 地址递:关注于递变量的地址,允许修改数据。 - 指针递:如果值递,则指针本身是副本;如果引用递,则可以修改指针。 常见误解:地址指针递常被视为相同,但指针递可以更灵活。 5. **性能**:从引用[^5],值消耗大,引用或地址消耗小。 生成相关问题: - 1. 在C++中,引用指针有什么区别? - 2. 如何避免在函数中修改原始数据? - 3. 为什么在C语言中没有引用递? </think> ### 指针递与地址递的区别 在C/C++编程中,指针递(Pointer Passing)地址递(Address Passing)是两个常被混淆的概念,但它们有本质区别。以下是逐步解释,基于C/C++语言的实现机制。 #### 1. **核心概念定义** - **地址递(Address Passing)**: 指将变量的内存地址(而非值本身)递给函数。函数通过该地址直接访问修改原始数据。这是底层指针机制的应用。 示例:在函数参数中使用指针类型(如 `int *ptr`),调用时递变量的地址(如 `&a`)。 效果:函数内对地址指向数据的修改会影响原始变量(因为实参形参共享同一内存地址)[^2][^4]。 - **指针递(Pointer Passing)**: 指指针变量的值(即指针本身存储的地址)。这分为两种情况: - **值指针(Pass by Value)**:指针的副本,函数内修改指针的值(如重新指向其他地址)不影响原始指针,但可以修改指针指向的数据。 - **引用指针(Pass by Reference,C++特有)**:指针的引用,函数内可直接修改原始指针本身(如改变其指向的地址)。 关键区别指针递更关注指针变量的行为,而非直接操作原始数据地址[^3][^5]。 #### 2. **核心区别详解** | 特性 | 地址递 | 指针递 | |--------------------|-----------------------------------------------|-----------------------------------------------| | **递内容** | 变量的内存地址(如 `&a`) | 指针变量的值(即地址) | | **参数类型** | 指针类型(如 `void func(int *ptr)`) | 指针类型(值递)或指针引用(如 `void func(int *&ptrRef)`) | | **修改原始数据** | 可以(通过解引用 `*ptr = ...`) | 值递:可修改数据(`*ptr = ...`),但不能修改原始指针;引用递:可修改数据原始指针 | | **修改原始指针本身** | 否(地址递不涉及指针变量) | 值递:否;引用递:是(如 `ptr = new_addr`) | | **性能消耗** | 低(仅地址,无额外数据拷贝)[^5] | 值递:中(指针副本开销);引用递:低 | | **安全性** | 需注意空指针解引用错误 | 引用递更安全(无空引用)[^3] | | **典型语言支持** | CC++ | C仅支持值指针;C++支持值引用递 | #### 3. **代码示例说明** 以下示例基于C/C++,展示两种递方式的差异。 **地址递示例**(修改原始数据): ```c #include <stdio.h> // 地址递:通过指针修改原始数据 void modifyData(int *ptr) { *ptr = 10; // 解引用修改地址指向的数据 } int main() { int a = 5; modifyData(&a); // 递变量a的地址 printf("a = %d\n", a); // 输出: a = 10(原始数据被修改) return 0; } ``` - 解释:`&a` 地址,`*ptr = 10` 直接修改 `a` 的值(实参形参共享地址)[^2]。 **指针递(值递)示例**(可修改数据,但不能修改原始指针): ```c #include <stdio.h> // 值指针指针副本 void changePointerValue(int *ptr) { int b = 20; ptr = &b; // 修改指针副本的指向(不影响原始指针) *ptr = 30; // 修改新指向的数据(但b是局部变量,危险!) } int main() { int a = 5; int *p = &a; changePointerValue(p); // 指针p的值(地址副本) printf("*p = %d\n", *p); // 输出: *p = 5(原始指针未变,数据未变) return 0; } ``` - 解释:`p` 的值(`&a`)被复制给形参 `ptr`,修改 `ptr` 不影响原始 `p`[^4]。 **指针递(引用递)示例**(C++,可修改原始指针): ```cpp #include <iostream> // 引用指针:通过引用修改原始指针 void changePointerRef(int *&ptrRef) { int b = 20; ptrRef = &b; // 直接修改原始指针的指向 } int main() { int a = 5; int *p = &a; changePointerRef(p); // 指针p的引用 std::cout << "*p = " << *p << std::endl; // 输出: *p = 20(原始指针被修改) return 0; } ``` - 解释:`ptrRef` 是 `p` 的引用,修改 `ptrRef` 会改变 `p` 的指向(但需注意 `b` 是局部变量,可能引发未定义行为)[^3]。 #### 4. **关键区别总结** - **目的不同**: - 地址递用于直接操作原始数据(如修改变量值)。 - 指针递用于操作指针本身(如改变指针指向或管理动态内存)。 - **底层机制**: 地址递本质是指针的简单应用;指针递涉及指针变量的值或引用,更灵活但更复杂。 - **风险**: 地址递需避免空指针指针递的引用方式在C++中更安全(无空引用),但值递可能引起指针副本的误解[^3][^5]。 - **性能**: 两者均高效(仅地址),但值指针有微小副本开销;值(非地址/指针)消耗更大,因为需拷贝整个数据[^5]。 #### 5. **常见误区澄清** - **“地址指针递是一回事”**: 错误。地址递是递变量的地址指针递是指针变量(可能值递或引用递)。地址递可视为指针递的子集。 - **“地址递不能修改数据”**: 错误。地址递通过解引用(`*ptr`)可直接修改原始数据[^1][^2]。 - **“C语言支持引用递”**: 错误。C语言仅支持值递(包括值指针);引用递是C++特性[^3]。 通过以上分析,您可以根据需求选择:若只需修改数据,用地址递;若需修改指针本身(如重定向),用C++的指针引用递。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值