int* a=b与int& a=b与int a=b
| int* a=b | int& a=b | int a=b |
|---|---|---|
| a存了b的地址 | a是b的别名 | 开辟一片新的地址存a,把b复制给a |
- int*表示a的类型是指针,这个指针指向的地址存的是整数
- int&表示a是b的别名(引用),a和b用的都是同一个地址,b怎么改,a就怎么变
- int表示a的类型就是整数
在函数中传参使用
void fun(auto& a){
a=10;
}
int b=20;
fun(b);
运行结果是a=b=10;因为a是b的别名,函数内部对a操作,就是对b操作
void fun(auto a){
a=10;
}
int b=20;
fun(b);
运行结果是b=20;因为函数中对a操作,a只是一个形参,不会对全局状态产生影响。
Gemini评价
你的理解非常准确,已经抓住了 C++ 中值传递、引用传递和指针传递的核心逻辑。
为了让你的知识体系更严谨,我针对你的思考笔记提供几点微调和深度补充:
1. 语法细节微调
在你的表格第一列 int* a = b 中,语法上有一点小瑕疵:
- 修正:应该是
int* a = &b;。 - 理由:
a是指针(存地址的),而b是整数(存值的)。你必须用取地址符&拿到b的地址,才能赋值给指针a。
2. 关于“别名”的底层真相
你在笔记中提到“a和b用的都是同一个地址”,这是完全正确的。
-
进阶理解:在函数传参
void fun(int& a)时,虽然语义上是“别名”,但编译器底层其实是通过指针(地址)来实现的。 -
直观比喻:
- 值传递 (
int a):给你一份文件的复印件。你在上面乱涂乱画,我手里的原件没影响。 - 引用传递 (
int& a):给你我办公室的钥匙。你进去把桌子烧了,我回来一看桌子确实没了。
- 值传递 (
3. 关于 auto 的小提醒
你在代码示例中使用了 void fun(auto& a),这是 C++20 才正式引入的特性(简写函数模板)。
- 在旧标准(如 C++11/14/17)中,函数形参不能直接写
auto,必须明确写类型(如int& a)或者使用template <typename T> void fun(T& a)。 - 既然你已经在使用 C++20 的语法,说明你接触的是比较现代的 C++,这个思路很棒。
4. 补充一个“指针传参”的对比
为了完善你的笔记,建议加上指针传参的情况,因为它介于两者之间:
void fun(int* a) {
*a = 10; // 通过地址找到原变量,修改它
}
int b = 20;
fun(&b); // 必须显式传入 b 的地址
// 结果:b 变成了 10
- 对比思考:引用传参(
int& a)在语法上像“值传递”一样简洁(不用写*和&),但在功能上却拥有“指针传递”的威力。这就是为什么 C++ 开发者更倾向于使用引用的原因。
总结你的思考:
你的逻辑完全正确。值传递看重“独立性”,引用传递看重“关联性”。 这种理解对于后续学习 C++ 的性能优化和内存管理至关重要。继续保持这种对比学习的方法!
我的修改
- 正确用法:int* a=&b;
- 指针传递
void fun(int* a){ *a=10; } int b=20; fun(&b);//这里要传递b的地址
Gemini二次评价
完美。你的修改非常到位,现在你的笔记逻辑链已经完整了:
- 值传递 (
int a):安全但有拷贝开销,不改变原值。 - 引用传递 (
int& a):语法最简洁,直接操作原值,效率高。 - 指针传递 (
int* a):需要手动处理地址(&b)和解引用(*a),灵活性最高(比如可以传入nullptr),同样操作原值。
最后给你的笔记加个“点睛之笔”:
在 C++ 开发中,有一个经典的选择原则,可以顺手记在你的思考里:
- 如果对象很小(如
int,double),用值传递。 - 如果对象很大(如
std::vector,std::string或自定义类),且不需要修改它,用const int& a(常量引用)。 - 如果需要修改原值,优先用引用;除非有特殊需求(如需要指针指向空或重新指向其他变量),才考虑指针。
你的学习思路非常扎实,这种对比总结是掌握 C++ 底层的最快路径!