C 指向数组的指针(手把手讲解)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战(已更新的所有项目都能学习) / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新开坑项目:《Spring AI 项目实战》 正在持续爆肝中,基于 Spring AI + Spring Boot 3.x + JDK 21..., 点击查看 ;
  • 《从零手撸:仿小红书(微服务架构)》 已完结,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;演示链接: http://116.62.199.48:7070 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观

在 C 语言编程中,"指向数组的指针" 是一个核心概念,它连接了指针与数组的底层逻辑,为高效操作数据结构提供了强大的工具。无论是处理动态内存、优化算法性能,还是理解函数参数传递的底层机制,掌握这一主题都至关重要。本文将通过循序渐进的讲解、生动的比喻和实际代码案例,帮助读者从基础到进阶逐步掌握 "C 指向数组的指针" 的核心知识。


一、理解数组与指针的基础关系

1.1 数组的本质:连续内存块

在 C 语言中,数组是一段连续的内存空间,每个元素按顺序存储。例如:

int arr[3] = {10, 20, 30};  

此数组占据 12 字节内存(假设 int 占 4 字节),元素 arr[0]arr[1]arr[2] 依次排列。

关键点:数组名(如 arr)本身是一个常量指针,指向数组的首地址。这意味着:

printf("%p\n", arr);       // 输出数组的首地址  
printf("%p\n", &arr[0]);   // 与上一行输出完全相同  

1.2 指针变量与数组的关系

指针变量可以指向数组的任意元素,而 "指向数组的指针" 则专门声明为指向整个数组类型的指针。两者的区别可通过以下示例理解:

int *ptr_to_element = &arr[0]; // 指向数组第一个元素的指针  
int (*ptr_to_array)[3] = &arr; // 指向整个数组的指针  

比喻

  • ptr_to_element 像是地图上的标记点,指向某个具体位置(如某栋楼)。
  • ptr_to_array 则像是一张地图的封面,代表整个区域(如整个街区)。

二、指向数组的指针的声明与使用

2.1 声明指向数组的指针

声明语法为:

element_type (*pointer_name)[array_size];  

例如:

int (*ptr)[5]; // 声明一个指向包含5个 int 元素的数组的指针  

注意

  • 指针名外的括号是必须的,否则会解释为 "指向 int 的指针数组"。
  • array_size 可以是常量或宏定义,但必须在编译时确定。

2.2 赋值与解引用

int arr[3] = {1, 2, 3};  
int (*ptr)[3] = &arr; // 正确赋值  

// 通过指针访问元素  
printf("%d\n", (*ptr)[1]); // 输出 2  

解引用原理

  • *ptr 获取数组本身(等价于 arr),
  • [1] 再通过索引访问元素。

2.3 指针的算术运算

指向数组的指针支持加减运算,但每次运算会跳过整个数组的大小。例如:

int arr1[3] = {10, 20, 30};  
int arr2[3] = {40, 50, 60};  
int (*ptr_array)[3] = &arr1;  

ptr_array++; // 指针移动到下一个数组的地址  
printf("%d\n", (*ptr_array)[0]); // 输出 40(假设 arr2 紧随 arr1)  

三、多维数组与指向数组的指针

3.1 二维数组的底层结构

二维数组本质是 "数组的数组"。例如:

int matrix[2][3] = {  
    {1, 2, 3},  
    {4, 5, 6}  
};  

此数组占据 24 字节内存,matrix 是指向 int[3] 类型的指针常量。

3.2 指向二维数组的指针

声明方式扩展为:

int (*ptr)[2][3]; // 指向 2x3 二维数组的指针  

但更常见的是声明指向行(一维数组)的指针:

int (*row_ptr)[3] = matrix; // 等价于 &matrix[0]  

访问元素

printf("%d\n", row_ptr[1][2]); // 输出 6  

3.3 动态二维数组的创建

通过 malloc 分配内存时,需明确数组大小:

int rows = 2, cols = 3;  
int (*dynamic_matrix)[cols] = malloc(rows * sizeof(int[cols]));  

// 初始化并访问  
for (int i = 0; i < rows; i++) {  
    for (int j = 0; j < cols; j++) {  
        dynamic_matrix[i][j] = i * cols + j + 1;  
    }  
}  

四、实际应用场景与案例分析

4.1 函数参数传递数组

将数组作为参数传递时,函数内部需使用指向数组的指针:

void print_array(int arr[], int size) { // 等价于 int *arr  
    for (int i = 0; i < size; i++) {  
        printf("%d ", arr[i]);  
    }  
}  

void print_2d(int (*matrix)[3], int rows) { // 明确列数  
    for (int i = 0; i < rows; i++) {  
        for (int j = 0; j < 3; j++) {  
            printf("%d ", matrix[i][j]);  
        }  
    }  
}  

4.2 指针遍历多维数组

通过指针实现矩阵转置:

void transpose(int (*src)[3], int (*dst)[2], int rows, int cols) {  
    for (int i = 0; i < rows; i++) {  
        for (int j = 0; j < cols; j++) {  
            dst[j][i] = src[i][j];  
        }  
    }  
}  

int main() {  
    int original[2][3] = {{1,2,3}, {4,5,6}};  
    int transposed[3][2];  
    transpose(original, transposed, 2, 3);  
    return 0;  
}  

4.3 指针与字符串处理

字符串本质是 char 数组,可通过指针操作实现功能:

void reverse_string(char (*str)[MAX_LEN], int len) {  
    for (int i = 0, j = len-1; i < j; i++, j--) {  
        char temp = (*str)[i];  
        (*str)[i] = (*str)[j];  
        (*str)[j] = temp;  
    }  
}  

五、常见误区与注意事项

5.1 指针与数组的等价性边界

  • 数组名在大多数情况下自动退化为指针,但以下情况例外:
    • 作为 sizeof& 运算符的操作数
    • 作为字符串字面量初始化数组

5.2 指针越界风险

int arr[5];  
int *ptr = arr;  
ptr += 5; // 越界访问 *ptr 是未定义行为  

5.3 动态内存的管理

使用 malloc 分配的指向数组的指针,必须用 free 释放:

int (*data)[10] = malloc(5 * sizeof(int[10]));  
// ... 使用后 ...  
free(data); // 正确释放,而非逐个元素释放  

六、结论与进阶方向

掌握 "C 指向数组的指针" 是理解 C 语言底层机制的重要步骤。通过本文的讲解,读者应能:

  1. 理解数组名与指针的底层关系
  2. 正确声明、操作指向数组的指针
  3. 在多维数组、函数参数等场景中灵活应用

进阶建议

  • 研究指针与结构体的结合使用
  • 探索动态内存分配的高级技巧(如 realloc
  • 分析标准库函数(如 qsort)中指针的运用

通过持续实践,读者将能够更自信地驾驭 C 语言的指针与数组系统,为开发高效、复杂的程序奠定坚实基础。

最新发布