题目

编写程序,设计两个变量并分别使用指针(Pointer)和左值引用(Lvalue Reference)进行绑定与修改。演示指针可以为 nullptr、可以改变指向(重定向),而引用必须在定义时初始化、终生依附且不可重定向(对引用的赋值本质是赋值给所引用的目标对象),并从汇编/地址层面打印比对变量与引用的内存地址。

输入格式:无需外部输入。

输出格式:依次打印变量、指针、引用的地址变化与数值同步情况。

数据范围与约定:内存语义与语法规则。

思路与算法

1. 引用的本质
语法层面上,引用是变量的纯粹“别名”(Alias),编译器不为引用单独开辟用户可见的存储空间;底层实现上,编译器通常将引用实现为带有解引用语义的 const 指针(T* const)。

2. 重定向语义陷阱
若对引用执行 ref = b,绝非让 ref 改为引用 b,而是将 b 的值拷贝赋给 ref 原本绑定的变量 a。此举极易在初学者中造成无意修改原变量数据的隐蔽 Bug。

3. 地址恒等性
对引用取地址 &ref 得到的是被绑定实体的真实内存地址,两者严格相等;而对指针取地址 &ptr 得到的是指针变量自身的存储地址。

完整程序

#include <iostream>

int main() {
    int a = 100;
    int b = 200;

    // 1. 指针:独立变量,存目标地址,可为空,可重定向
    int* ptr = &a;
    // 2. 引用:必须初始化,是 a 的别名
    int& ref = a;

    std::cout << std::boolalpha;
    std::cout << "--- 1. 初始状态与内存地址 ---\n";
    std::cout << "a 的数值: " << a << ", b 的数值: " << b << "\n";
    std::cout << "&ref == &a: " << (&ref == &a) << "\n";
    std::cout << "&ref == &b: " << (&ref == &b) << "\n";
    std::cout << "ptr 指向 a: " << (ptr == &a) << "\n";
    std::cout << "ptr 自身地址是否等于 a 的地址: " << (static_cast<const void*>(&ptr) == static_cast<const void*>(&a)) << "\n\n";

    // 3. 修改引用与指针指向的值
    std::cout << "--- 2. 通过引用修改 a ---\n";
    ref = 150;
    std::cout << "执行 ref = 150 后的 a: " << a << "\n\n";

    // 4. 重定向测试:指针 vs 引用
    std::cout << "--- 3. 改变指向 vs 假重定向 ---\n";
    ptr = &b; // 指针合法重定向,指向 b
    std::cout << "指针 ptr 重定向后指向的值: " << *ptr << " (指向 b)\n";
    std::cout << "ptr 现在指向 b: " << (ptr == &b) << "\n";

    ref = b;  // 注意:这绝不是将 ref 重新绑定到 b,而是执行 a = b!
    std::cout << "执行 ref = b 后 a 的值: " << a << " (a 被覆盖为 b 的值)\n";
    std::cout << "此时 &ref == &a: " << (&ref == &a) << "\n";
    std::cout << "此时 &ref == &b: " << (&ref == &b) << "\n";

    return 0;
}

运行示例

输出:

--- 1. 初始状态与内存地址 ---
a 的数值: 100, b 的数值: 200
&ref == &a: true
&ref == &b: false
ptr 指向 a: true
ptr 自身地址是否等于 a 的地址: false

--- 2. 通过引用修改 a ---
执行 ref = 150 后的 a: 150

--- 3. 改变指向 vs 假重定向 ---
指针 ptr 重定向后指向的值: 200 (指向 b)
ptr 现在指向 b: true
执行 ref = b 后 a 的值: 200 (a 被覆盖为 b 的值)
此时 &ref == &a: true
此时 &ref == &b: false