int x = 5; // ① 申请一个盒子,贴标签 x,里面写数字 5
int *p = &x; // ② 申请第二个盒子,贴标签 p
// 把“盒子 x 的门牌号”抄到 p 里
Python 和 Java 都把“实参本身的重新指向”给禁掉了
而C/C++ 可以把实参本身改掉,于是诞生了指针
在函数里交换两个整数 #include <stdio.h> void swap(int *a, int *b) { int tmp = *a; *a = *b; *b = tmp; } int main(void) { int x = 1, y = 2; swap(&x, &y); // 传入地址 printf("x=%d y=%d\n", x, y); // x=2 y=1 return 0; } main栈帧 swap栈帧 ┌-----┐ ┌-----┐ │ x 1 │ ◄-----┤ a ◄─┼---- 指向 x │ y 2 │ ◄-----┤ b ◄─┼---- 指向 y └-----┘ └-----┘
&x
得到的地址就是真实地址本身,传进去后 swap
里的 a
、b
不是副本哦,而是那个地址在 C 里发生了什么(图 + 真值) main 栈帧 swap 栈帧 ┌------┐ ┌------┐ │ x 1 │ ◄─ a ----┤ int*a│ (a 里存 0x7ff...100) │ y 2 │ ◄─ b ----┤ int*b│ (b 里存 0x7ff...104) └------┘ └------┘ &x 产生 0x7ff...100(x 的真实地址) 这个 8 字节地址值 被压栈 传给形参 a,但地址本身不是副本; 你可以把 a 当成“指向 x 的指针变量”,通过 *a 直接读写 x。
java Java 里发生了什么(传引用副本) void foo(Node n) { // n 是“引用副本” n.value = 99; // ✅ 改对象内部 n = new Node(); // ❌ 只改副本指向,外部无感 } Node p = new Node(5); foo(p); 内存示意: main 栈帧 foo 栈帧 ┌------┐ ┌------┐ │ p ----┼─┐ │ n ----┼─┐ (副本,值同 p) └------┘ │ └------┘ │ ▼ ▼ [Node] (指向同一对象) 传进去的仍是 8 byte 的“地址值”,但它是 拷贝; 因此 n = new Node(); 只是改副本,外层 p 丝毫不动。
定义时的 *
:只是指针类型的标记
int *p = &x;
int *p;
1. 先声明:p 是一个指针 p = &x;
2. 再赋值:把 x 的地址存进去
*
不是运算符,只是类型说明符,“p 指向 x” 或 “p 存了 x 的地址”。*
:才是“解引用”运算符,真正去内存取值/存值printf("%d\n", *p);
// 这里的 * 才是运算符,叫做“解引用” *p = 10;
// 也是运算符,把 10 写到 p 所指的地址
这里的 *
是解引用运算符,“取 p 指向的内容” 或 “把 p 指向的那块内存设为 10”
*a = *b
就是把 b
指向的值写到 a
指向的那块内存
&
取地址,*
按地址拿值;
param = new_obj
)只是改了这个副本,外层实参仍然指向原来的对象。# 1. 不可变对象(类似 Java 的基本类型) def foo(x): x = 99 # 重新绑定:只改副本 a = 5 foo(a) print(a) # 5,外层不变 # 2. 可变对象(类似 Java 的引用类型) def bar(lst): lst.append(99) # 改对象内部 lst = [7, 8] # 重新绑定:只改副本 b = [1, 2] bar(b) print(b) # [1, 2, 99],原对象被改;但 lst = [7,8] 对外层无影响
Java 的规则
原始类型:绝对改不了 java void foo(int x) { x = 10; // 只改了副本 } int a = 5; foo(a); System.out.println(a); // 还是 5 引用类型:只能改对象内部,改不了实参本身指向谁 class Node { int v; Node(int v){this.v=v;} } void foo(Node n) { n.v = 10; // ✅ 能改对象内部 n = new Node(99); // ❌ 只改了副本指向,外部不受影响 } Node p = new Node(5); foo(p); System.out.println(p.v); // 10,不是 99
java 和 Python 都是“值传递”
不是语言缺陷,而是一种设计权衡(trade-off)。
把“能不能把实参本身改掉”这件事放在语言设计层面,Java 和 C 各走了不同路线,没有绝对优劣,而是一种有意为之的安全设计。