指针(Pointer)

一句话目标:理解”变量住在内存的哪个地址”,并用一种专门的类型 —— 指针 —— 去保存和使用这个地址。


第一部分:变量放在哪?—— 内存地址

程序运行时,每个变量都住在内存里的某个地址(门牌号)。用 & 取出变量的地址:

int n = 35;
cout << n;    // 35   —— 值
cout << &n;   // 0x7ffe...  —— n 所在的地址

&取地址运算符。每个变量都有自己的地址。


第二部分:指针 —— 专门存地址的类型

指针是一种新的数据类型,专门用来存放其他数据的地址

定义指针时要声明它指向什么类型的数据:

int  n = 35;
int* p;       // p 是"指向 int 的指针"
p = &n;       // 让 p 存放 n 的地址(p 指向 n)
 
int* q = &n;  // 定义时直接初始化

读法:int* p —— “p 是一个指针,指向 int”。指向的类型可以是基本类型、结构、类、数组、函数,甚至 void


第三部分:解引用 —— 通过指针访问变量

* 解引用,顺着地址找到那个变量的值:

int n = 35;
int* p = &n;
cout << *p;    // 35  —— 顺着 p 找到 n 的值
*p = 100;      // 通过 p 修改 n
cout << n;     // 100 —— n 真的被改了!

⚠️ 两个符号别搞混:

  • 定义时的 int* p 和解引用的 *p 都用 *
  • &n 是取地址,*p 是取”指针指向的值”。它们互为逆操作。

第四部分:指针运算

指针能做加减,而且很聪明:p + 1 不是地址加 1 字节,而是跳到下一个元素(按指向类型的大小自动算)。

int a[5] = {10, 20, 30, 40, 50};
int* p = a;        // 数组名就是首元素地址,p 指向 a[0]
cout << *p;        // 10
cout << *(p + 1);  // 20  —— 跳到下一个 int
p++;               // p 现在指向 a[1]

所以 a[i] 等价于 *(a + i) —— 这正是指针与数组的本质联系(呼应 06.数组(一维与二维))。


第五部分:sizeof 运算符

sizeof 算出某类型 / 变量占多少字节

cout << sizeof(int);     // 4
cout << sizeof(double);  // 8
cout << sizeof(char);    // 1
int a[10];
cout << sizeof(a);       // 40  —— 10 个 int

可用于基本类型、结构体、数组、类、指针。


第六部分:了解一下(不必深究)

  • 指针数组:一个数组,每个元素都是指针。
  • 二级指针:指向指针的指针(int** pp),入门阶段知道有这回事即可。
  • 指针与字符串char* 可以指向字符串,C 风格字符串就靠它。

小结

  • 每个变量有地址& 取地址。
  • 指针是存地址的类型:int* p = &n;
  • *p 解引用取值,可读可改。
  • 指针 +1 跳一个元素;a[i] == *(a+i),指针与数组同源。
  • sizeof 算字节数。

课后小练

  1. 定义 int n,用指针 p 修改 n 的值并输出,体会”通过地址改值”。
  2. 用指针遍历数组 a[5] 并求和(用 *(p+i))。
  3. 输出 intdoublechar、某数组的 sizeof