用 &a 可获取 int 变量 a 的内存地址,类型为 int*;但直接 cout << &a 会输出地址值,而非预期内容。

用 & 获取 int 变量的内存地址,但别直接打印指针值
直接对 int 变量写 &a 就能得到它的地址,类型是 int*。但很多人一上来就 cout ,结果看到一串十六进制数字——这其实是地址值,但默认被当成了 <code>void* 输出,有些平台会转成十进制,有些则显示不完整或报错。
- 正确做法是显式转成
uintptr_t或用printf的%p格式符 -
&a本身不是“取内容”,而是求变量在栈/数据段中的起始字节位置,它不依赖变量是否初始化 - 如果
a是寄存器变量(极少见)或被编译器优化掉(比如没被使用过),&a可能触发编译错误:error: lvalue required as unary '&' operand
& 不能用于字面量、表达式或临时对象
这是最常踩的坑:有人写 &(x + y) 或 &42,编译器直接报错。因为 & 要求操作数是左值(lvalue),也就是有确定内存位置、能被取地址的实体。
- 合法:
int x = 5; int* p = &x; - 非法:
int* p = &5;→error: lvalue required as unary '&' operand - 非法:
int* p = &(x + 1);→ 同样报 lvalue 错误,x + 1是纯右值(prvalue) - 例外:C++11 起,可以对 const 引用绑定的临时对象“间接取址”,但本质仍是取引用所绑定的那个临时对象的地址,不是直接对字面量取址
数组名、函数名和 & 的行为差异
数组名(如 int arr[3])本身不是指针,但多数上下文会隐式转为指向首元素的指针;而 &arr 是取整个数组的地址,类型是 int(*)[3],值虽和 arr 相同,但语义和可运算性完全不同。
-
arr + 1指向第 2 个int(偏移 4 字节) -
&arr + 1指向“下一个同样大小的数组”,偏移3 * sizeof(int)(通常 12 字节) - 函数名
foo也会隐式转为函数指针,&foo合法且等价,但sizeof(&foo)无意义(函数类型不可 sizeof) - 结构体变量整体可取址:
&s得到struct S*,但注意结构体可能有填充字节,&s.field不一定等于(char*)&s + offsetof(...)(虽然通常是)
调试时看地址,别靠 printf("%p", &x) 乱猜生命周期
局部 int 变量的地址每次运行都可能不同(ASLR),甚至同一函数多次调用也不同;但只要没出作用域,这个地址就一直有效。很多人以为“地址变了说明变量被回收了”,其实只是栈帧重用了而已。
立即学习“C++免费学习笔记(深入)”;
- 释放栈空间不是“擦除地址”,而是后续调用可能覆盖那块内存 —— 所以返回局部变量地址是未定义行为,哪怕你刚拿到它
- 全局/静态
int地址稳定,但链接时可能被重定位(PIE 关闭时更明显) - 用
gdb查看print &x比代码里打印更可靠,尤其涉及优化(-O2下变量可能根本不出现在内存中)
地址本身不难拿,难的是搞清它背后绑定的内存是否还归你管。越想“稳稳地用这个地址”,越得盯紧变量的生存期和存储期。










