C++: 指针基础

最后更新:2026-08-26

前面的课程里,变量存在内存的某个位置。

但那个"位置"到底在哪?能不能直接访问它?

指针就是用来存地址的变量——它能让你直接操作内存。


1. 什么是指针?

(1) 1.1 生活中的指针

生活场景 程序中的对应
你家的地址(如"北京市朝阳区...") 指针(存地址)
你家的房子(地址指向的实际建筑) 变量(地址指向的内存空间)

指针的本质: 一个存地址的变量。

(2) 1.2 为什么需要指针?

  1. 动态内存分配(后面会学 new / delete
  2. 函数需要修改外部变量(传指针给函数)
  3. 处理数组(数组名就是指针)
  4. 实现复杂数据结构(链表、树、图)


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:先理解核心概念,再通过实践例子来巩固。

📖 小节


📝 作业

  1. 基础题 (Difficulty ⭐): 声明一个 int 变量 x = 10,再声明一个 int* 指针 p 指向 x。输出 x 的值和 *p 的值。

  2. 进阶题 (Difficulty ⭐⭐): 写一个函数 void addTen(int* p),给指针指向的变量加 10。在 main 里测试。

  3. 挑战题 (Difficulty ⭐⭐⭐): 写一个程序,声明三个 int 变量 a, b, c,再声明三个指针分别指向它们。通过指针把三个变量的值都改成 100,然后输出。


9. 🚀 下一步

学会了指针基础,接下来我们学习 指针与数组(第23课)—— 理解数组名就是指针,以及指针算术。

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏