C++: 指针算术进阶

最后更新:2026-08-26

第23课我们学了指针算术的基础(p + np - q)。

但指针算术还有很多细节——比如指针能比较大小吗void* 指针是什么?指针的指针又是什么?


1. 指针比较

(1) 1.1 指针能比较大小吗?

能! 但只有指向同一个数组的指针比较才有意义。

▶ 示例 2:基础编程实践(难度⭐)

CPP
#include <iostream>

int main() {
 int arr[5] = {10, 20, 30, 40, 50};
 int* p1 = &arr[0];
 int* p2 = &arr[3];
 
 if (p1 < p2) { // ✅ p1 指向的元素在 p2 前面
 std::cout << "p1 在 p2 前面" << std::endl;
 }
 
 if (p2 - p1 == 3) { // ✅ 两个指针相隔 3 个元素
 std::cout << "p1 和 p2 相隔 3 个元素" << std::endl;
 }
 
 return 0;
}
▶ 试一试

输出:

TEXT 📖 仅展示
p1 在 p2 前面
p1 和 p2 相隔 3 个元素

💡 重点: 指针比较的是地址大小(即元素在数组中的位置)。


(2) 1.2 指针相等比较

CPP
#include <iostream>

int main() {
 int x = 5;
 int* p1 = &x;
 int* p2 = &x;
 
 if (p1 == p2) { // ✅ 两个指针指向同一个变量
 std::cout << "p1 和 p2 指向同一个变量" << std::endl;
 }
 
 int y = 10;
 int* p3 = &x;
 int* p4 = &y;
 
 if (p3 != p4) { // ✅ 两个指针指向不同的变量
 std::cout << "p3 和 p4 指向不同的变量" << std::endl;
 }
 
 return 0;
}


2. void* 指针

(1) 2.1 什么是 void* 指针?

void*通用指针——可以指向任何类型的数据。

CPP
#include <iostream>

int main() {
 int x = 5;
 double y = 3.14;
 char c = 'A';
 
 void* p1 = &x; // ✅ void* 可以指向 int
 void* p2 = &y; // ✅ void* 可以指向 double
 void* p3 = &c; // ✅ void* 可以指向 char
 
 return 0;
}

💡 特点:


(2) 2.2 void* 的用途

用途一:写通用函数(后面会学 std::memcpy 就是用 void*

CPP
#include <iostream>
#include <cstring>

int main() {
 int arr1[5] = {1, 2, 3, 4, 5};
 int arr2[5];
 
 // std::memcpy 用 void* 接收任何类型的指针
 std::memcpy(arr2, arr1, 5 * sizeof(int));
 
 for (int i = 0; i < 5; i++) {
 std::cout << arr2[i] << " ";
 }
 std::cout << std::endl;
 
 return 0;
}

用途二:动态内存分配(后面会学 malloc 返回 void*


(3) 2.3 void* 的转换

要用 void* 指向的值,必须转换成具体类型的指针

CPP
#include <iostream>

int main() {
 int x = 5;
 void* p = &x; // void* 指向 int
 
 // ❌ 错误:不能直接解引用 void*
 // std::cout << *p << std::endl;
 
 // ✅ 正确:先转换成 int*
 int* intPtr = static_cast<int*>(p);
 std::cout << *intPtr << std::endl; // 输出 5
 
 return 0;
}

💡 提示: static_cast 是 C++ 的类型转换运算符(后面会学),比 C 语言的 (int*)p 更安全。



3. 多级指针(指针的指针)

(1) 3.1 什么是指针的指针?

指针的指针就是存指针地址的指针(套娃)。

CPP
#include <iostream>

int main() {
 int x = 5;
 int* p = &x; // p 指向 x
 int** pp = &p; // pp 指向 p(指针的指针)
 
 std::cout << "x = " << x << std::endl;
 std::cout << "*p = " << *p << std::endl; // 解引用一次:得到 x 的值
 std::cout << "**pp = " << **pp << std::endl; // 解引用两次:得到 x 的值
 
 return 0;
}

(2) 3.2 多级指针的声明

声明 含义
int x; xint
int* p; pint*指向 int 的指针
int** pp; ppint**指向 int* 的指针
int*** ppp; pppint***指向 int** 的指针

💡 读法: 从右往左读。


(3) 3.3 多级指针的用途

用途一:动态二维数组(后面会学)

CPP
// 动态分配一个 3×4 的二维数组
int** matrix = new int*[3]; // matrix 是指针的指针
for (int i = 0; i < 3; i++) {
 matrix[i] = new int[4];
}

用途二:函数需要修改指针(少见,了解即可)

CPP
#include <iostream>

void allocateInt(int** ptr) {
 *ptr = new int(5); // 修改 *ptr(即修改原指针)
}

int main() {
 int* p = nullptr;
 allocateInt(&p); // 传指针的地址
 std::cout << *p << std::endl; // 输出 5
 delete p; // 释放内存
 return 0;
}


4. 指针和 const 的组合

(1) 4.1 四种组合

声明 含义 能不能改指针 能不能改指向的值
int* p; 普通指针 ✅ 能 ✅ 能
const int* p; 指向 const int 的指针 ✅ 能 ❌ 不能
int* const p = &x; const 指针(必须初始化) ❌ 不能 ✅ 能
const int* const p = &x; 指向 const 的 const 指针 ❌ 不能 ❌ 不能

💡 记忆技巧: 从右往左读。


(2) 4.2 示例:const int*(常用)

CPP
#include <iostream>

void printArray(const int* arr, int size) {
 for (int i = 0; i < size; i++) {
 std::cout << arr[i] << " ";
 }
 std::cout << std::endl;
 
 // ❌ 不能修改:arr[i] = 0; // 编译报错
}

int main() {
 int arr[5] = {1, 2, 3, 4, 5};
 printArray(arr, 5);
 return 0;
}

输出:

TEXT 📖 仅展示
1 2 3 4 5

💡 重点: const int* arr最常用的函数参数类型——表示"我只读,不修改"。



5. 实战:用指针实现字符串复制

▶ 示例 1:手写 strcpy(难度⭐⭐)

CPP
#include <iostream>

void myStrcpy(char* dest, const char* src) {
 while (*src != '\0') {
 *dest = *src; // 复制字符
 dest++; // 移动指针
 src++;
 }
 *dest = '\0'; // 加结束符
}

int main() {
 char src[] = "Hello";
 char dest[20];
 
 myStrcpy(dest, src);
 std::cout << "src = " << src << std::endl;
 std::cout << "dest = " << dest << std::endl;
 
 return 0;
}
▶ 试一试

输出:

TEXT 📖 仅展示
src = Hello
dest = Hello

💡 提示: 这个程序用到了指针算术解引用,是理解指针的绝佳练习。


▶ 示例 3:用指针遍历数组(难度⭐)

CPP
#include <iostream>

int main() {
    int arr[] = {10, 20, 30, 40, 50};
    int* p = arr; // p 指向数组首元素

    std::cout << "用指针遍历数组:" << std::endl;
    for (int i = 0; i < 5; i++) {
        std::cout << "*p = " << *p << std::endl;
        p++; // 指针移动到下一个元素
    }

    // 指针相减计算元素个数
    int* end = arr + 5;
    std::cout << "元素个数:" << end - arr << std::endl;

    return 0;
}
▶ 试一试

输出:

TEXT 📖 仅展示
用指针遍历数组:
*p = 10
*p = 20
*p = 30
*p = 40
*p = 50
元素个数:5

❓ 常见问题

Q:为什么 void 不能解引用?* A:因为 void 是没有大小的类型——编译器不知道要读 1 个字节、4 个字节、还是 8 个字节。

必须转换成具体类型的指针(如 int*double*),编译器才知道步长。

Q:多级指针有什么用? A:实际项目中,int 最常见于: > 1. 动态二维数组(如 new int*[3]) > 2. 函数需要修改指针本身(如 void foo(int p) 可以修改 p 指向哪里)

超过两级的指针(int*** 等)不推荐——太难理解了。

Q:const int 和 int const 一样吗? A:一样!以下两种写法等价: > > const int p; // 推荐 > int const p; // 等价,但不常用 > > > 但 int* const p 不一样——这是 const 指针(不能改指向)。


📖 小节


📝 作业

  1. 基础题 (Difficulty ⭐): 声明一个 int 变量 x = 5,再声明一个 int* 指针 p 指向 x,再声明一个 int** 指针 pp 指向 p。输出 x*p**pp,验证它们相等。

  2. 进阶题 (Difficulty ⭐⭐): 写一个函数 void swap(int** a, int** b),交换两个指针的指向。

TEXT 📖 仅展示
输入:p1 指向 x,p2 指向 y
调用 swap(&p1, &p2)
输出:p1 指向 y,p2 指向 x
  1. 挑战题 (Difficulty ⭐⭐⭐):void* 和指针算术,手写一个 myMemcpy 函数:
  2. 函数原型:void myMemcpy(void* dest, const void* src, size_t n)
  3. 功能:从 src 复制 n 个字节到 dest
  4. 提示:按字节复制(用 char* 做指针算术)

6. 🚀 下一步

学会了指针进阶,接下来我们学习 引用(Reference)(第25课)—— 指针的"安全版",C++ 的重要特性!

Web-Tutorial.com

Web-Tutorial 技术团队

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

100%

🙏 帮我们做得更好

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

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