第八章:指针深入解析
8.1 指针基本概念与声明
指针的本质
指针是存储内存地址的变量,通过地址直接访问数据。
• 类比:指针类似房间号,通过地址找到数据所在的内存位置。
声明与初始化
数据类型 *指针变量名; // 声明指针
指针变量名 = &目标变量; // 初始化(取目标变量地址)
示例:
int num = 10;
int *p = # // p指向num的地址
printf("%p\n", p); // 输出地址,如0x7ffd3a4c
printf("%d\n", *p); // 解引用,输出10
关键操作符:
• &
:取地址符(获取变量地址)。
• *
:解引用符(访问指针指向的值)。
指针类型的重要性:
• 指针类型决定了解引用时的内存解释方式(如int*
和char*
访问同一地址时读取的字节数不同)。
8.2 指针运算与数组关系
指针运算规则:
- 加减整数:指针移动
n * sizeof(类型)
字节。
- 指针相减:结果为两个地址间的元素个数(非字节数)。
指针与数组名的关系:
• 数组名在大多数情况下是首元素地址的常量指针(如arr
等价于&arr[0]
)。
示例:指针遍历数组
int arr[] = {10, 20, 30};
int *p = arr; // p指向arr[0]
for (int i = 0; i < 3; i++) {
printf("%d ", *(p + i)); // 输出:10 20 30
}
多维数组指针:
int matrix[2][3] = {{1, 2, 3}, {4, 5, 6}};
int (*ptr)[3] = matrix; // 指向含3个元素的数组的指针
printf("%d", ptr[1][2]); // 输出:6
8.3 指针与字符串操作
字符指针的优势:
• 动态修改字符串内容(不同于字符串字面量的不可变性)。
示例:指针操作字符串
char str[] = "Hello";
char *p = str;
// 遍历字符串
while (*p != '\0') {
printf("%c ", *p); // 输出:H e l l o
p++;
}
// 修改字符串
str[0] = 'h'; // 允许修改
p = "World"; // p指向只读常量区(不可修改*p的值)
8.4 指针数组与数组指针
类型 | 定义 | 用途 |
指针数组 | 数组元素为指针 | 存储多个字符串或动态地址 |
数组指针 | 指针指向整个数组 | 处理多维数组 |
示例对比:
// 指针数组(每个元素是char*)
char *names[] = {"Alice", "Bob", "Charlie"};
// 数组指针(指向含3个int的数组)
int (*ptr)[3];
int arr[2][3] = {0};
ptr = arr; // ptr指向arr[0]
8.5 动态内存管理(malloc/calloc/realloc/free)
核心函数(需包含 <stdlib.h>
):
函数 | 功能 | 示例 |
malloc(size) | 分配未初始化的内存块 | int *p = malloc(5 * sizeof(int)); |
calloc(n, size) | 分配并初始化为0的内存块 | int *p = calloc(5, sizeof(int)); |
realloc(ptr, size) | 调整已分配内存块的大小 | p = realloc(p, 10 * sizeof(int)); |
free(ptr) | 释放内存 | free(p); |
动态数组示例:
int *arr = malloc(5 * sizeof(int)); // 分配5个int的空间
if (arr == NULL) { // 必须检查分配是否成功
printf("内存分配失败");
exit(1);
}
for (int i = 0; i < 5; i++) {
arr[i] = i * 2; // 初始化
}
free(arr); // 释放内存
注意事项:
• 内存泄漏:分配后未释放。
• 悬挂指针:释放后仍访问指针(应将指针置为NULL
)。
8.6 函数指针与应用
函数指针定义:
指向函数的指针,用于动态调用函数或实现回调机制。
声明与使用:
// 声明函数指针类型(与目标函数签名匹配)
int (*funcPtr)(int, int);
// 指向加法函数
int add(int a, int b) { return a + b; }
funcPtr = add;
// 通过指针调用函数
int result = funcPtr(3, 5); // 结果:8
应用场景:
- 回调函数:将函数作为参数传递。
- 策略模式:运行时选择不同算法。
示例:通用排序函数
#include <stdio.h>
// 定义比较函数指针类型
typedef int (*CompareFunc)(int, int);
// 冒泡排序(支持自定义比较规则)
void bubbleSort(int arr[], int size, CompareFunc compare) {
for (int i = 0; i < size-1; i++) {
for (int j = 0; j < size-i-1; j++) {
if (compare(arr[j], arr[j+1])) {
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
// 比较函数1:升序
int ascending(int a, int b) { return a > b; }
// 比较函数2:降序
int descending(int a, int b) { return a < b; }
int main() {
int arr[] = {5, 2, 8, 1, 4};
bubbleSort(arr, 5, ascending); // 升序排序
return 0;
}
总结
- 指针的核心价值:
• 直接操作内存,提升效率(如数组遍历、字符串处理)。
• 实现动态数据结构(链表、树等)。
- 避坑指南:
• 避免野指针(未初始化的指针)。
• 动态内存必须配对释放。
- 高阶应用:
• 函数指针支持灵活的多态行为。
• 多级指针(如int**
)用于处理复杂结构。