指针与多维数组的关系
多维数组在内存中实际是线性存储的。例如一个二维数组int arr[3][4],可以理解为由3个一维数组组成,每个一维数组包含4个元素。数组名arr是指向第一个子数组(arr[0])的指针,arr + 1指向arr[1]。
访问元素arr[i][j]等价于*(*(arr + i) + j)。arr[i]本身是一个指针,指向该行的首元素,而*(arr + i)解引用后得到该行的首地址。
指针数组与数组指针的区别
指针数组是一个数组,其元素均为指针。例如int *ptr_arr[5]表示一个包含5个int*类型元素的数组,常用于存储不同长度的字符串数组:
char *strs[] = {"Hello", "World", "C"};
数组指针是指向数组的指针,如int (*arr_ptr)[4]指向一个包含4个int元素的一维数组。通常用于操作二维数组的行:
int matrix[3][4];
int (*p)[4] = matrix; // p指向matrix的首行
动态内存分配的高级应用
使用malloc和free可以动态分配多维数组。例如分配一个3x4的二维数组:
int **arr = (int **)malloc(3 * sizeof(int *));
for (int i = 0; i < 3; i++) {
arr[i] = (int *)malloc(4 * sizeof(int));
}
释放内存时需逆向操作:
for (int i = 0; i < 3; i++) {
free(arr[i]);
}
free(arr);
函数指针与回调机制
函数指针允许动态调用不同函数。例如定义一个函数指针类型并赋值:
int (*func_ptr)(int, int) = &add; // 假设add是已定义的函数
int result = func_ptr(2, 3); // 等价于add(2, 3)
回调函数常用于事件处理或排序算法。例如qsort的标准用法:
int compare(const void *a, const void *b) {
return (*(int *)a - *(int *)b);
}
int arr[] = {5, 2, 8};
qsort(arr, 3, sizeof(int), compare);
指针与结构体的高级用法
结构体指针可通过->操作符访问成员。例如链表的节点定义和操作:
typedef struct Node {
int data;
struct Node *next;
} Node;
Node *head = (Node *)malloc(sizeof(Node));
head->data = 10;
head->next = NULL;
指向结构体数组的指针可通过偏移访问:
Node nodes[5];
Node *ptr = nodes;
(ptr + 2)->data = 20; // 访问第三个元素
指针的常见陷阱与调试技巧
野指针问题常由未初始化或已释放的指针引起。建议初始化时置为NULL,释放后立即置空:
int *p = NULL;
p = (int *)malloc(sizeof(int));
free(p);
p = NULL;
内存泄漏可通过工具如Valgrind检测。数组越界可能破坏相邻内存,需严格检查索引范围。
性能优化与指针运算
指针算术比数组索引在某些情况下更高效。例如遍历数组时:
int arr[10];
int *end = arr + 10;
for (int *p = arr; p < end; p++) {
*p = 0;
}
避免频繁解引用多层指针,缓存中间结果以提高性能。

被折叠的 条评论
为什么被折叠?



