深入解析C++中的指针数组与指向指针的指针

Ruby
Ruby
发布时间:2026-10-14| 5人浏览过
原创

指针数组是元素为指针的数组,常用于管理一组相关对象(如字符串)。指向指针的指针则用于存储其他指针的地址。本文通过字符串排序实例,深入剖析这两者的定义、声明方式及内存访问逻辑。

指针数组的定义与声明

当一个数组的所有元素均为指针型数据时,该数组被称为指针数组。其核心特征是:数组中的每一个元素都相当于一个独立的指针变量,它们各自存储的是地址值。

第1步:掌握指针数组的声明语法

一维指针数组的标准定义形式如下:

类型名 *数组名[数组长度];
// 例如:
int *p[4];

在解析声明时需注意运算符优先级:[ ](数组下标)的优先级高于 *(间接访问)。因此 p[4] 先结合,表示 p 是一个包含 4 个元素的数组;随后 * 说明这些元素是指针类型,每个元素都能指向整型变量。

注意:切勿将其误写为 int (*p)[4]。后者表示的是一个指向含有 4 个元素的一维数组的指针(数组指针),两者含义截然不同。

指针数组最典型的应用场景是管理一组字符串。由于每个数组元素都是一个指针,分别指向不同的字符串常量或缓冲区,这使得字符串的处理更加灵活。

第2步:使用指针数组进行字符串排序(实战示例)

以下程序演示了如何利用指针数组和选择排序法,对一组编程语言名称进行字典序排序。

#include <iostream>
#include <string.h>
using namespace std;

// 函数声明
void sort(char *p[], int n);
void print(char *p[], int n);

int main() {
    // 定义指针数组,初始化指向各个字符串常量的首地址
    char *name[] = {"C", "C++", "PHP", "ASP", "ASP.NET", "C#", "JAVA", "BASIC", "PASCAL", "COBOL"};
    int n = 10;

    // 调用排序函数
    sort(name, n);
    // 输出结果
    print(name, n);
    return 0;
}

// 选择排序:交换指针指向,而非移动字符串本身
void sort(char *p[], int n) {
    char *temp;
    for (int i = 0; i < n; i++) {
        int k = i; // 假设当前最小元素下标为 k
        for (int j = i + 1; j < n; j++) {
            if (strcmp(p[j], p[k]) < 0) {
                k = j; // 找到更小的元素
            }
        }
        // 如果找到的最小元素不是当前元素,则交换指针
        if (k != i) {
            temp = p[k];
            p[k] = p[i];
            p[i] = temp;
        }
    }
}

// 打印数组内容
void print(char *p[], int n) {
    for (int i = 0; i < n; i++) {
        cout << p[i] << endl;
    }
}

原理分析:

  1. 实参与形参的关系:在 main 函数中定义的 name 数组,其 10 个元素分别是各字符串字面量起始地址的拷贝。调用 sort(name, n) 时,将数组首地址传给形参 p,此时 p 和 name 指向同一个内存区域,操作其中一个即操作另一个。
  2. 非破坏性排序:排序过程中,我们交换的是指针的值(地址),而不是复制庞大的字符串数据。这极大地提高了处理大型字符串集合的效率。
  3. 替代写法:print 函数也可以使用指针算术实现,效果等价:
void print(char *p[], int n) {
    char *q;
    int i = 0;
    while (i < n) {
        q = *(p + i++); // p+i 是第 i 个元素的地址,解引用后得到该元素持有的字符串地址
        cout << q << endl;
    }
}

指向指针的指针(二级指针)

指向指针数据的指针称为指向指针的指针,通常称为“二级指针”。它在 C/C++ 中常用于需要修改指针本身(而非指针所指向的内容)的场景,或者在处理动态二维数组及指针数组时作为参数传递。

第1步:建立二级指针与指针数组的联系

回到上面的例子,如果在 main 函数中执行以下操作:

char *name[] = {...};
char **p;
p = name; // 注意:这里是将 name 的首地址赋值给 p,因为 name 退化为 char**

虽然 name 是数组名,但在多数表达式中会退化为指向其第一个元素的指针。对于字符指针数组 char *[],其类型为 char **。因此 char **p = name; 是合法的,此时 p 指向 name[0] 这个指针变量。

第2步:解析二级指针的多层解引用行为

以下代码展示了如何通过二级指针访问指针数组中间的元素:

#include <iostream>
using namespace std;

int main() {
    char *name[] = {"C", "C++", "PHP", "ASP", "ASP.NET", "C#", "JAVA", "BASIC", "PASCAL", "COBOL"};
    
    char **p;
    p = name + 2; // p 指向 name[2] 所在的内存位置(即指向 "PHP" 的那个指针变量)
    
    // 第一层解引用:获取 name[2] 的值(即字符串 "PHP" 的首地址)
    cout << *p << endl; 
    
    // 第二层解引用:获取字符串 "PHP" 的第一个字符 'P'
    cout << **p << endl; 
    
    return 0;
}

层次解析:

  • p:是一个二级指针,存储的是 name[2] 这个指针变量的地址。
  • *p:是对二级指针的一次解引用,结果是 name[2] 中存储的值,即指向字符串 "PHP" 首地址的指针(等价于 name[2] 或 "PHP")。
  • **p:是两次解引用,先得到字符串地址,再获取该地址处的字符。因为定义为指向 char 类型的指针,所以输出结果为字符 'P'。

以上就是C++中指针数组与指向指针的指针的详细内容,更多关于C++指针进阶资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。