深入解析C++中的指针数组与指向指针的指针
指针数组是元素为指针的数组,常用于管理一组相关对象(如字符串)。指向指针的指针则用于存储其他指针的地址。本文通过字符串排序实例,深入剖析这两者的定义、声明方式及内存访问逻辑。
指针数组的定义与声明
当一个数组的所有元素均为指针型数据时,该数组被称为指针数组。其核心特征是:数组中的每一个元素都相当于一个独立的指针变量,它们各自存储的是地址值。
第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;
}
}
原理分析:
- 实参与形参的关系:在
main函数中定义的name数组,其 10 个元素分别是各字符串字面量起始地址的拷贝。调用sort(name, n)时,将数组首地址传给形参p,此时p和name指向同一个内存区域,操作其中一个即操作另一个。 - 非破坏性排序:排序过程中,我们交换的是指针的值(地址),而不是复制庞大的字符串数据。这极大地提高了处理大型字符串集合的效率。
- 替代写法:
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++指针进阶资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









