第5章 指针与数组

一、核心概念关系

指针与数组是C语言最密切相关的两个概念,本章揭示了它们的本质联系:

  • 数组名本质上是数组首元素的常量指针
  • 指针运算与数组下标访问具有等价性(a[i]*(a+i)
  • 指针提供了比数组下标更灵活的操作方式

二、指针基础深入

1. 指针声明与初始化

int *p; // 声明指向int的指针
int x = 10;
p = &x; // p指向x
*p = 20; // 通过指针修改x的值

2. 指针运算特性

  • 算术运算p ± n 的实际地址为 p ± n*sizeof(*p)
  • 关系运算:比较指针在内存中的位置关系
  • 减法运算:得到两指针间的元素个数(非字节数)

三、指针与数组的等价性

1. 数组访问的两种形式

int a[10];
a[3] = 5; // 数组下标形式
*(a + 3) = 5; // 指针运算形式(编译器实际处理方式)

2. 关键区别

特性 数组名 指针变量
存储位置 编译时确定 运行时动态分配
可修改性 不可修改 可修改
sizeof结果 数组总字节数 指针大小

四、高级指针应用

1. 指针数组 vs 数组指针

int *p[10]; // 指针数组:10个int指针组成的数组
int (*p)[10]; // 数组指针:指向含10个int的数组的指针

2. 多维数组处理

二维数组作为参数传递的三种等价形式:

void func(int a[][10]);
void func(int (*a)[10]);
void func(int **a); // 仅当动态分配时适用

3. 命令行参数处理

int main(int argc, char *argv[]) {
// argv[0] = 程序名
// argv[1...] = 命令行参数
}

五、复杂声明解析

使用"右左法则"解析复杂指针声明:

  1. 从标识符开始
  2. 先向右看,再向左看
  3. 遇到括号先解析括号内

示例:

int (*(*fp)(int))[10];
// fp是指向函数的指针,该函数接受int参数,返回指向含10个int的数组的指针

六、内存管理函数

1. 动态分配函数族

void *malloc(size_t size); // 未初始化
void *calloc(size_t n, size_t size); // 初始化为0
void *realloc(void *ptr, size_t size); // 调整大小
void free(void *ptr); // 释放内存

2. 使用规范

  • 检查返回值是否为NULL
  • 释放后立即将指针置NULL
  • 避免"悬挂指针"和"内存泄漏"

七、典型编程模式

1. 字符串处理

// 字符串复制实现
void strcpy(char *s, char *t) {
while (*s++ = *t++);
}

2. 高效数组遍历

for (p = arr; p < arr + len; p++) {
// 使用*p访问元素
}

3. 函数指针应用

int (*compare)(void *, void *); // 比较函数指针
qsort(base, n, size, compare); // 标准库排序函数

八、重要注意事项

  1. 指针初始化:未初始化的指针是"野指针"
  2. 边界检查:指针运算可能越界
  3. 类型匹配:避免不兼容指针类型的强制转换
  4. const修饰
const int *p; // 指向常量的指针
int *const p; // 指针本身为常量

九、本章核心要点图示

+-------------------+ +-------------------+
| 指针系统 |<----->| 数组系统 |
+-------------------+ +-------------------+
^ | ^ |
| v | v
+-------------------+ +-------------------+
| 内存直接访问能力 | | 连续存储结构 |
+-------------------+ +-------------------+

本章奠定了C语言高效系统编程的基础,理解指针与数组的关系是掌握C语言内存管理和高效算法的关键。后续章节的复杂数据结构(如链表、树等)都建立在这些概念之上。

posted @ 2025-05-08 14:21  MachineGaming  阅读(24)  评论(0)    收藏  举报