有了 chatgpt 或 deepseek 后,学习成本与时间大大降低。想起之前自学 c 语言时花了累计一年看谭浩强的教材,花了一年多看一本 C++ 800多页的大厚书,最终也没有学明白,尤其是指针云里雾里的。感觉借助生成式 AI ,要不了多久,我应该也可以像上手 Java 那样上手 C++ 的大型程序了。
这篇博客基于两个 AI 的回答,整理了指针的相关知识点。
1. 指针的本质
指针本质上是存储地址的变量。普通变量存储的是值,而指针存储的是某个变量的地址,它指向这个变量在内存中的位置。
int a = 10; // 变量 a,存储整数 10
int* p = &a; // 指针 p,存储 a 的地址
在这段代码中:
a
是普通变量,存储数值10
。&a
获取a
的内存地址。p
是指针变量,它存储的是a
的地址,而不是a
的值。
2. 指针的存储和工作方式
2.1 变量的存储
假设 a
的地址是 0x100
,那么变量 a
在内存中的存储如下:
变量名 | 地址 | 值 |
---|---|---|
a | 0x100 | 10 |
2.2 指针的存储
指针 p
存储的是 a
的地址 0x100
:
变量名 | 地址 | 值 |
---|---|---|
p | 0x200 | 0x100 |
a | 0x100 | 10 |
3. 指针的基本操作
3.1 指针声明
指针的声明格式:
数据类型 *指针变量名;
例如:
int* p; // p 是一个指向 int 类型的指针
double* q; // q 是一个指向 double 类型的指针
3.2 赋值(存储地址)
int a = 10;
int* p = &a; // p 存储 a 的地址
3.3 取值(解析地址)
cout << *p << endl; // 输出 10
p
是一个变量,存储了另外一个变量a
的地址。*p
解析指针p
指向的地址,即得到a
的值。
3.4 通过指针修改值
*p = 20; // 通过指针修改 a 的值
cout << a; // 输出 20
4. 指针和数组
数组名本质上是指向数组第一个元素的指针,即数组第一个元素的地址。
int arr[] = {1, 2, 3};
int* p = arr; // p 指向 arr[0],相当于 int* p = &arr[0]
cout << *p << endl; // 输出 1
cout << *(p + 1) << endl; // 输出 2
cout << *(p + 2) << endl; // 输出 3
p + 1
指向arr[1]
,p + 2
指向arr[2]
。
5. 指针的指针
指针可以指向另一个指针:
int a = 10;
int* p = &a; // p 指向 a,即 p 的值为 a 的地址
int** pp = &p; // pp 指向 p,即 pp 的值为 p 的地址,并不是 *pp 的值为 p 的地址
// 其实,*pp 表示解析 pp 的值,得到的反而是 p 的值,即 a 的地址
cout << **pp << endl; // 输出 10
p
存储的是a
的地址**pp
中,里面的*
解析pp
的值(p
的地址),得到的是p
的值(a
的地址)**pp
中,外面的*
解析p
的值(a
的地址),得到的是a
的值- 因此
**pp
访问a
。
我实际测试:
变量名 | 地址 | 值 |
---|---|---|
a | 0x1523d0000(a的地址) | 10 |
p | 0x1523d8000 (p的地址) | 0x1523d0000 (a的地址) |
pp | 0x152838000 | 0x1523d8000(p的地址) |
*p | 0x1523d0000 (实际是a的地址,因为*p的值为a) | 10 |
*pp | 0x1523d8000 (相当于 &*pp,因此等同于pp的值,即 p 的地址) | 0x1523d0000(a的地址) |
**pp | 0x1523d0000 (实际是a的地址,因为**p的值为a) | 10 |
这个指针套指针,我混淆了很多年了。总结了,一句话:对于形如 int** pp = &p
,
- 不管指针变量前面几个星号,指针变量的值为等号右边变量的地址;根据星号解析地址的作用,从里到外一个一个解析就好了。
并且,当 p 为有效指针时,
*&p
=&*p
6. 指针与动态内存
C++ 允许使用 new
分配堆内存:
int* p = new int(10); // 分配一个 int
cout << *p << endl; // 输出 10
delete p; // 释放内存
new
申请内存,返回指针。delete
释放内存。
7. 指针的本质总结
- 指针是一个变量,存储的是某个变量的地址,而不是值。
*
用于解引用,访问指针指向的变量。- 指针可以指向数组,指针运算可用于遍历数组。
- 指针可以指向指针,实现多级指针。
- 指针可以用于动态内存管理,
new
和delete
操作堆内存。
指针的核心就是存储地址,然后可以通过 *
访问该地址处的数据。指针在 C 和 C++ 中非常重要,理解指针有助于掌握底层内存管理和数据操作!