C 语言数组与指针
外观
C语言数组与指针是C语言中两个紧密关联的核心概念。理解它们的关系对于高效操作内存、字符串处理以及动态数据结构至关重要。本文将系统讲解数组与指针的基础、内存模型、运算规则及实际应用。
基础概念[编辑 | 编辑源代码]
数组的定义[编辑 | 编辑源代码]
数组是相同类型元素的连续集合,通过索引访问。声明格式如下:
int arr[5] = {10, 20, 30, 40, 50}; // 声明并初始化长度为5的整型数组
指针的本质[编辑 | 编辑源代码]
指针是存储内存地址的变量,其类型决定了解引用时的操作方式:
int *ptr; // 声明指向整型的指针
ptr = &arr[0]; // 指针指向数组首元素
数组与指针的关系[编辑 | 编辑源代码]
内存模型[编辑 | 编辑源代码]
数组名在多数情况下会退化为指向首元素的指针。例如,arr
等价于&arr[0]
。
访问元素的等价性[编辑 | 编辑源代码]
以下四种访问方式完全等效:
arr[2] // 数组下标访问
*(arr + 2) // 指针算术运算
ptr[2] // 指针下标语法
*(ptr + 2) // 指针解引用
输出均为:30
指针算术运算[编辑 | 编辑源代码]
指针加减整数时,实际移动的字节数为:
示例:
int *ptr1 = &arr[1];
int *ptr2 = ptr1 + 3; // 移动3个int大小的距离
printf("%td\n", ptr2 - ptr1); // 输出:3
多维数组与指针[编辑 | 编辑源代码]
二维数组可看作"数组的数组"。对于int matrix[3][4]
:
matrix
类型是int (*)[4]
(指向含4个元素的数组的指针)matrix[i][j]
等价于*(*(matrix + i) + j)
实际应用案例[编辑 | 编辑源代码]
案例1:字符串反转[编辑 | 编辑源代码]
void reverseString(char *str) {
char *end = str;
while (*end) end++; // 找到字符串结尾
end--; // 跳过NULL终止符
while (str < end) {
char temp = *str;
*str++ = *end;
*end-- = temp;
}
}
// 输入:"hello"
// 输出:"olleh"
案例2:动态二维数组[编辑 | 编辑源代码]
int **createMatrix(int rows, int cols) {
int **matrix = malloc(rows * sizeof(int *));
for (int i = 0; i < rows; i++) {
matrix[i] = malloc(cols * sizeof(int));
}
return matrix;
}
// 使用后需逐行free
常见误区[编辑 | 编辑源代码]
错误用法 | 正确方式 | 说明 |
---|---|---|
ptr++ | 数组名不是可修改的左值
| ||
sizeof(arr) | 指针大小≠数组大小
| ||
char str[] = "literal"; | 字符串字面量不可修改
|
高级主题[编辑 | 编辑源代码]
数组指针 vs 指针数组[编辑 | 编辑源代码]
- 数组指针:指向数组的指针,如
int (*ptr)[10]
- 指针数组:元素为指针的数组,如
int *arr[10]
函数指针与数组[编辑 | 编辑源代码]
函数指针数组可用于实现状态机或命令模式:
void (*operations[3])(void) = {func1, func2, func3};
operations[0](); // 调用func1
总结[编辑 | 编辑源代码]
关键点:
- 数组名在表达式中退化为指针(除了
sizeof
和&
操作) - 指针算术运算基于类型大小
- 多维数组需要理解"行指针"概念
- 动态内存分配时需严格管理指针
掌握数组与指针的关系将显著提升C语言编程能力,特别是在系统编程和性能敏感场景中。建议通过内存绘图加深理解。