C语言指针专题三 -- 指针数组

目录

1. 指针数组的核心原理

2. 指针数组与二维数组的区别

3. 编程实例

4. 常见陷阱与防御

5. 总结


1. 指针数组的核心原理

指针数组是一种特殊数组,其所有元素均为指针类型。每个元素存储一个内存地址,可指向不同类型的数据(通常指向同类型数据)。
核心特性

  1. 声明语法数据类型 *数组名[长度];

    • 例如:int *arr[5]; 表示一个包含5个int*类型指针的数组。

  2. 内存布局

    • 指针数组本身在内存中连续存储(存储的是指针值,即地址),但这些指针指向的实际数据可以是分散的。

  3. 典型应用

    • 管理多个字符串(如char *str_list[])。

    • 动态创建“锯齿状”二维数组(每行长度不同)。

    • 实现多级数据结构(如指向指针的指针数组)。

  4. 初始化与存储

            初始化方式与一般数组初始化相同,指针数组每个元素指向初始化内存区域。

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[])。

    • 构建稀疏矩阵(部分行有数据,部分行为空)。

    • 实现复杂数据结构(如树、图的邻接表)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

W说编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值