C++: 指针基础
最后更新:2026-08-26
前面的课程里,变量存在内存的某个位置。
但那个"位置"到底在哪?能不能直接访问它?
指针就是用来存地址的变量——它能让你直接操作内存。
1. 什么是指针?
(1) 1.1 生活中的指针
| 生活场景 | 程序中的对应 |
|---|---|
| 你家的地址(如"北京市朝阳区...") | 指针(存地址) |
| 你家的房子(地址指向的实际建筑) | 变量(地址指向的内存空间) |
指针的本质: 一个存地址的变量。
(2) 1.2 为什么需要指针?
- 动态内存分配(后面会学
new/delete) - 函数需要修改外部变量(传指针给函数)
- 处理数组(数组名就是指针)
- 实现复杂数据结构(链表、树、图)
2. 指针的声明与初始化
(1) 2.1 声明指针
语法:
▶ 示例 2:代码示例(难度⭐)
CPP
Type* pointerName;
输出:
TEXT
📖 仅展示
(程序输出)
示例:
CPP
#include <iostream>
int main() {
int* pInt; // 指向 int 的指针
double* pDouble; // 指向 double 的指针
char* pChar; // 指向 char 的指针
return 0;
}
💡 重点: 类型* 表示"指向该类型的指针"。
(2) 2.2 取地址运算符(&)
& 用来获取变量的地址。
CPP
#include <iostream>
int main() {
int x = 5;
std::cout << "x 的值:" << x << std::endl;
std::cout << "x 的地址:" << &x << std::endl; // 输出类似 0x7ffd4a3b
return 0;
}
输出(示例):
TEXT
📖 仅展示
x 的值:5
x 的地址:0x7ffd4a3b
💡 提示: 地址的具体格式取决于系统和编译器。
(3) 2.3 初始化指针
CPP
#include <iostream>
int main() {
int x = 5;
int* p = &x; // p 指向 x(p 存的是 x 的地址)
std::cout << "x 的地址:" << &x << std::endl;
std::cout << "p 的值:" << p << std::endl; // 和 &x 一样
return 0;
}
3. 解引用(Dereference)
(1) 3.1 解引用运算符(*)
* 用来访问指针指向的值。
CPP
#include <iostream>
int main() {
int x = 5;
int* p = &x; // p 指向 x
std::cout << "x = " << x << std::endl; // 5
std::cout << "*p = " << *p << std::endl; // 5(解引用)
return 0;
}
💡 重点: *p 就是 x!
(2) 3.2 通过指针修改变量的值
CPP
#include <iostream>
int main() {
int x = 5;
int* p = &x;
std::cout << "修改前:x = " << x << std::endl; // 5
*p = 100; // 通过指针修改 x 的值
std::cout << "修改后:x = " << x << std::endl; // 100
return 0;
}
4. 指针的大小
(1) 4.1 sizeof 指针
CPP
#include <iostream>
int main() {
int* pInt;
double* pDouble;
char* pChar;
std::cout << "int* 大小:" << sizeof(pInt) << " 字节" << std::endl;
std::cout << "double* 大小:" << sizeof(pDouble) << " 字节" << std::endl;
std::cout << "char* 大小:" << sizeof(pChar) << " 字节" << std::endl;
return 0;
}
输出(64位系统):
TEXT
📖 仅展示
int* 大小:8 字节
double* 大小:8 字节
char* 大小:8 字节
💡 重点: 所有指针的大小都一样(64位系统是 8 字节,32位系统是 4 字节)——因为它们存的都是地址。
5. 空指针(nullptr)
(1) 5.1 什么是空指针?
空指针是不指向任何对象的指针。
CPP
#include <iostream>
int main() {
int* p = nullptr; // 空指针(C++11 之后推荐)
if (p == nullptr) {
std::cout << "p 是空指针" << std::endl;
}
return 0;
}
💡 提示: C++11 之前用 NULL(其实是 0),但现在推荐用 nullptr。
(2) 5.2 解引用空指针会崩溃
CPP
#include <iostream>
int main() {
int* p = nullptr;
std::cout << *p << std::endl; // ❌ 未定义行为!可能崩溃
return 0;
}
运行结果:
CPP
Segmentation fault (core dumped) // Linux
或
CPP
Process finished with exit code -1073741819 // Windows
⚠️ 永远不要解引用空指针!
6. 指针作为函数参数
(1) 6.1 问题:函数需要修改外部变量
CPP
#include <iostream>
void modifyValue(int x) {
x = 100; // ❌ 修改的是副本,不影响原变量
}
int main() {
int a = 5;
modifyValue(a);
std::cout << "a = " << a << std::endl; // 5(没变)
return 0;
}
(2) 6.2 解决方法:传指针
CPP
#include <iostream>
void modifyValue(int* p) {
*p = 100; // ✅ 通过指针修改原变量
}
int main() {
int a = 5;
modifyValue(&a); // 传地址
std::cout << "a = " << a << std::endl; // 100(变了!)
return 0;
}
7. 实战:交换两个变量的值
▶ 示例 1:用指针实现 swap(难度⭐)
CPP
#include <iostream>
void swap(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int x = 3, y = 5;
std::cout << "交换前:x = " << x << ", y = " << y << std::endl;
swap(&x, &y); // 传地址
std::cout << "交换后:x = " << x << ", y = " << y << std::endl;
return 0;
}
输出:
TEXT
📖 仅展示
交换前:x = 3, y = 5
交换后:x = 5, y = 3
💡 提示: 后面会学引用——用引用实现 swap 更简洁。
8. 常见错误
(1) 8.1 解引用未初始化的指针
CPP
#include <iostream>
int main() {
int* p; // ❌ 未初始化(野指针)
std::cout << *p << std::endl; // ❌ 未定义行为!
return 0;
}
修复: 初始化为 nullptr,或指向一个已存在的变量。
(2) 8.2 指针类型不匹配
CPP
#include <iostream>
int main() {
int x = 5;
double* p = &x; // ❌ 错误:int* 不能指向 int
return 0;
}
编译错误信息:
TEXT
📖 仅展示
error: cannot convert 'int*' to 'double*' in initialization
▶ 示例 3:指针与数组(难度⭐)
CPP
#include <iostream>
int main() {
int arr[] = {10, 20, 30, 40, 50};
int* p = arr; // 数组名就是首元素地址
for (int i = 0; i < 5; i++) {
std::cout << "arr[" << i << "] = " << *(p + i) << std::endl;
}
return 0;
}
输出:
TEXT
📖 仅展示
arr[0] = 10
arr[1] = 20
arr[2] = 30
arr[3] = 40
arr[4] = 50
💡 提示:数组名
arr 就是首元素的地址,等同于 &arr[0]。用指针遍历数组时,*(p + i) 等同于 p[i] 或 arr[i]。
❓ 常见问题
Q 指针和引用的区别是什么?
A 后面会详细讲,这里先简单说: > - 指针可以指向
nullptr,引用必须初始化 > - 指针可以重新指向其他变量,引用一旦绑定就不能改 > - 指针需要用 *p 解引用,引用直接用变量名Q:关于pointers basics最重要的是什么? A:先理解核心概念,再通过实践例子来巩固。
📖 小节
- 指针是存地址的变量
- 声明:
Type* pointerName; - 取地址:
&variableName - 解引用:
*pointerName - 空指针:
nullptr - 永远不要解引用空指针或野指针
📝 作业
-
基础题 (Difficulty ⭐): 声明一个
int变量x = 10,再声明一个int*指针p指向x。输出x的值和*p的值。 -
进阶题 (Difficulty ⭐⭐): 写一个函数
void addTen(int* p),给指针指向的变量加 10。在main里测试。 -
挑战题 (Difficulty ⭐⭐⭐): 写一个程序,声明三个
int变量a, b, c,再声明三个指针分别指向它们。通过指针把三个变量的值都改成 100,然后输出。
- 指针是存储内存地址的变量
- & 取地址,* 解引用访问指向的值
- 声明方式:Type* pointerName(如 int* p;)
- 空指针 nullptr(C++11)替代 NULL
- 指针指向同一块内存,一个改另一个也受影响
9. 🚀 下一步
学会了指针基础,接下来我们学习 指针与数组(第23课)—— 理解数组名就是指针,以及指针算术。