📄 一句话概括
指针变量的声明格式是 类型 *指针名;,赋值时给它一个地址:int *p = &a;。读作"p 是一个指针,它指向一个 int"。类型必须和目标一致——int * 只能指向 int,不能指向 double。另外,指针自己也有地址(可以用 &p 取到),别和它装着的地址搞混。
📝 本节和前面几节的关系
7.4 讲了"指针是记门牌号的小纸条"。这一节学"小纸条怎么写、怎么填"。声明指针的零件全是旧朋友:类型(第二章)、* 号(第三章的乘法符号,在这里换了身份)、标识符规则(2.3.1)。下一节 7.4.2 才讲"照着门牌号找上门"的动作(* 解引用)——那是本节最重要的一步。
一、声明一个指针变量
int a = 10;
int *p = &a; // 声明 p 是指针,并让它指向 a
逐字拆开读:
| 片段 | 读作 |
|---|---|
int |
p 指向的那户人家,里面装的是 int |
* |
"p 是个指针"(这个星号属于声明语法,不是乘法) |
p |
指针变量自己的名字 |
= &a |
初始化:把 a 的地址填进 p |
一句话翻译:int *p = &a; = "p 是一张纸条,上面抄着 a 家的门牌号"。
星号写哪儿都行,但有个著名的坑
int *p; // ✅ 常见写法
int* p; // ✅ 也合法(有人觉得这样更能体现"p 的类型是 int*")
int * p; // ✅ 也合法
int *p, q; // ⚠️ 陷阱!p 是 int*,但 q 是普普通通的 int
int *p, *q; // ✅ 两个都是指针
最后一个坑必须记住:星号只跟紧它后面的那一个名字。写 int *p, q; 时,q 得到一个 int,不是指针。一行声明多个指针,每个前面都要有 *。
二、指针里有地址,指针自己也有地址
int a = 10;
int *p = &a;
// p 里装着 a 的地址
cout << p << endl; // 0x61ff0c ← a 的地址
// p 自己也是一块内存,也有地址
cout << &p << endl; // 0x61ff08 ← p 自己的地址
图示(两个门牌号、一张纸条):
p(一张纸条) a(一个盒子)
┌───────────────┐ ┌──────────┐
│ 0x61ff0c │ ──────► │ 10 │
└───────────────┘ └──────────┘
0x61ff08 0x61ff0c
(纸条自己在哪) (纸条上写的地址)
"指向"的准确含义:p 里的那个数,恰好就是 a 的地址。所以顺着 p 找过去,就能找到 a。
别混淆三个东西:
| 写法 | 是什么 |
|---|---|
a |
a 的值(10) |
&a |
a 的地址(和 p 里的内容相同) |
p |
一个变量,它的值是 a 的地址 |
&p |
p 这个变量自己的地址 |
三、实例05:输出变量的地址值
#include <iostream>
using namespace std;
int main() {
int a = 10;
int *p = &a; // p 指向 a
cout << "a 的值 = " << a << endl;
cout << "a 的地址 = " << &a << endl;
cout << "p 里存的 = " << p << endl; // 与 &a 相同
cout << "p 自己的地址 = " << &p << endl;
// 判断 p 是否真的指向 a
if (p == &a) cout << "p 确实指向 a" << endl;
return 0;
}
看到什么算成功:
a 的值 = 10
a 的地址 = 0x61ff0c
p 里存的 = 0x61ff0c ← 和上一行一模一样
p 自己的地址 = 0x61ff08 ← 另一个地址
p 确实指向 a
中间两行是本节的核心证据:p 和 &a 打印出来完全相同——这就是"p 指向 a"的字面含义。而 &p 是另一个地址,说明指针自己也占地儿。
30 秒实验:加一句 int *q = &a;,再打印 q——和 p 打印出的地址完全一样。这叫"多个指针可以指向同一户人家",后面 7.6.1 讲函数传地址时正是靠这个特性。
四、常见误区
- "
int *p = &a;里的*是乘法"——不是。这是声明语法里的星号,意思是"p 是指针"。不过它确实和 3.1.1 的乘号是同一个字符——看位置和上下文辨认(7.4.2 会把三种身份一次讲清)。 - "
int *p, q;声明了两个指针"——只声明了p一个指针,q是普通的int。星号只跟紧后一个名字。 - "指针不初始化也能用"——极其危险。
int *p;里的内容是垃圾值(2.3.2),它可能指向任何地方;这时去用它,就是 7.4.4 要讲的"野指针"。 - "指针类型随便写,反正都是地址"——必须匹配。
double *p = &a;(a 是 int)会编译报错。因为类型决定了"顺着这个地址该怎么读、读几个字节"。 - "
cout << p打印出的是它指向的值"——不是,打印的是地址。想取值要写*p(下一节)。
自测三问(点开对答案)
1. 怎么声明一个指向 `double` 的指针 `pd`,并让它指向变量 `d`?——`double *pd = &d;` 2. `int *p, q;` 里 `q` 是什么类型?——普通的 `int`(不是指针)。星号只跟紧 `p`。 3. `p` 和 `&p` 有什么区别?——`p` 里装着**别人**的地址;`&p` 是 **p 自己**在内存里的地址。- ☐ 7.4.2 指针运算符和取地址运算符(下一节)
相关笔记
- 指针 —— 指针是什么、为什么要有
- 指针运算符和取地址运算符 —— 下一节:
*怎么取值 - 变量的声明及赋值 —— 未初始化=垃圾值(野指针的根源)
- 🔷 C++基础 · 索引 —— 全课路线图