目录
1. 指针数组的核心原理
2. 指针数组与二维数组的区别
3. 编程实例
4. 常见陷阱与防御
5. 总结
1. 指针数组的核心原理
指针数组是一种特殊数组,其所有元素均为指针类型。每个元素存储一个内存地址,可指向不同类型的数据(通常指向同类型数据)。
核心特性:
-
声明语法:
数据类型 *数组名[长度];
-
例如:
int *arr[5];
表示一个包含5个int*
类型指针的数组。
-
-
内存布局:
-
指针数组本身在内存中连续存储(存储的是指针值,即地址),但这些指针指向的实际数据可以是分散的。
-
-
典型应用:
-
管理多个字符串(如
char *str_list[]
)。 -
动态创建“锯齿状”二维数组(每行长度不同)。
-
实现多级数据结构(如指向指针的指针数组)。
-
-
初始化与存储
初始化方式与一般数组初始化相同,指针数组每个元素指向初始化内存区域。
int main()
{
int b[2][3];
int *pb[2];
//初始化方法一
pb[0]=b[0];
pb[1]=b[1];
//初始化方法二
//int b[2][3];
//int *pb[ ]={b[0],b[1]};
……
return 0;
}
2. 指针数组与二维数组的区别
当使用指针数组处理二维数组时,其步长为二维数组行增长单元,如图所示
3. 编程实例
实例1:字符串指针数组(管理多个字符串)
#include <stdio.h>
int main() {
// 声明并初始化字符串指针数组
char *fruits[] = {"Apple", "Banana", "Cherry", "Date"};
int count = sizeof(fruits) / sizeof(fruits[0]);
// 遍历输出所有字符串
for (int i = 0; i < count; i++) {
printf("Fruit %d: %s\n", i + 1, fruits[i]);
}
return 0;
}
输出:
Fruit 1: Apple
Fruit 2: Banana
Fruit 3: Cherry
Fruit 4: Date
内存示意图:
指针数组(栈内存) 只读内存区(字符串字面量)
+--------+ +-----------------+
| 0x1000 | ------> | 'A' 'p' 'p' ... | "Apple"
+--------+ +-----------------+
| 0x2000 | ------> | 'B' 'a' 'n' ... | "Banana"
+--------+ +-----------------+
| 0x3000 | ------> | 'C' 'h' 'e' ... | "Cherry"
+--------+ +-----------------+
| 0x4000 | ------> | 'D' 'a' 't' ... | "Date"
+--------+ +-----------------+
实例2:动态创建“锯齿状”二维数组
#include <stdio.h>
#include <stdlib.h>
int main() {
// 声明指针数组(3个int*类型指针)
int *matrix[3];
// 动态分配每行内存(每行长度不同)
matrix[0] = (int*)malloc(2 * sizeof(int)); // 第0行2个元素
matrix[1] = (int*)malloc(3 * sizeof(int)); // 第1行3个元素
matrix[2] = (int*)malloc(1 * sizeof(int)); // 第2行1个元素
// 初始化数据
matrix[0][0] = 1; matrix[0][1] = 2;
matrix[1][0] = 3; matrix[1][1] = 4; matrix[1][2] = 5;
matrix[2][0] = 6;
// 打印锯齿状数组
for (int i = 0; i < 3; i++) {
int cols = (i == 0) ? 2 : (i == 1) ? 3 : 1;
for (int j = 0; j < cols; j++) {
printf("matrix[%d][%d] = %d ", i, j, matrix[i][j]);
}
printf("\n");
}
// 释放内存
for (int i = 0; i < 3; i++) free(matrix[i]);
return 0;
}
输出:
matrix[0][0] = 1 matrix[0][1] = 2
matrix[1][0] = 3 matrix[1][1] = 4 matrix[1][2] = 5
matrix[2][0] = 6
内存示意图:
指针数组(栈内存) 堆内存(动态分配)
+--------+ +-----+-----+
| 0x5000 | ------> | 1 | 2 | // 第0行
+--------+ +-----+-----+
| 0x6000 | ------> | 3 | 4 | 5 // 第1行
+--------+ +-----+-----+-----+
| 0x7000 | ------> | 6 | // 第2行
+--------+ +-----+
实例3:多级指针数组(二维指针数组)
#include <stdio.h>
int main() {
// 声明二维指针数组(3行,每行2个char*指针)
char *names[3][2] = {
{"Alice", "Bob"},
{"Charlie", "David"},
{"Eve", "Frank"}
};
// 遍历输出所有名字
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
printf("names[%d][%d]: %s\n", i, j, names[i][j]);
}
}
return 0;
}
输出:
names[0][0]: Alice
names[0][1]: Bob
names[1][0]: Charlie
names[1][1]: David
names[2][0]: Eve
names[2][1]: Frank
4. 常见陷阱与防御
1. 未初始化指针直接使用
int *arr[3];
printf("%d", arr[0][0]); // 错误!指针未指向有效内存
防御:确保指针指向合法内存后再访问。
2. 内存泄漏
int *arr[3];
arr[0] = malloc(10 * sizeof(int));
// 忘记释放arr[0]
防御:动态分配的内存必须逐个释放。
3. 越界访问
char *strs[2] = {"Hello", "World"};
printf("%s", strs[2]); // 越界访问(有效索引为0和1)
防御:严格检查数组索引范围。
5. 总结
-
指针数组通过存储多个指针实现灵活的数据管理,尤其适合处理字符串集合或动态二维数组。
-
与二维数组相比,指针数组支持 各行长度不同 和 动态内存分配,但需手动管理内存。
-
使用场景:
-
管理多个字符串(如命令行参数
char *argv[]
)。 -
构建稀疏矩阵(部分行有数据,部分行为空)。
-
实现复杂数据结构(如树、图的邻接表)。
-