跳转到内容

C 语言数组与指针

来自代码酷


C语言数组与指针是C语言中两个紧密关联的核心概念。理解它们的关系对于高效操作内存、字符串处理以及动态数据结构至关重要。本文将系统讲解数组与指针的基础、内存模型、运算规则及实际应用。

基础概念[编辑 | 编辑源代码]

数组的定义[编辑 | 编辑源代码]

数组是相同类型元素的连续集合,通过索引访问。声明格式如下:

int arr[5] = {10, 20, 30, 40, 50}; // 声明并初始化长度为5的整型数组

指针的本质[编辑 | 编辑源代码]

指针是存储内存地址的变量,其类型决定了解引用时的操作方式:

int *ptr; // 声明指向整型的指针
ptr = &arr[0]; // 指针指向数组首元素

数组与指针的关系[编辑 | 编辑源代码]

内存模型[编辑 | 编辑源代码]

数组名在多数情况下会退化为指向首元素的指针。例如,arr等价于&arr[0]

graph LR A[数组arr] --> B[元素0: 10] A --> C[元素1: 20] A --> D[...] P[指针ptr] --> B

访问元素的等价性[编辑 | 编辑源代码]

以下四种访问方式完全等效:

arr[2]    // 数组下标访问
*(arr + 2) // 指针算术运算
ptr[2]    // 指针下标语法
*(ptr + 2) // 指针解引用

输出均为:30

指针算术运算[编辑 | 编辑源代码]

指针加减整数时,实际移动的字节数为:偏移量×sizeof(类型)

示例:

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)

graph TB M[matrix] --> R0[行0] M --> R1[行1] M --> R2[行2] R0 --> C00[元素00] R0 --> C01[元素01] R1 --> C10[元素10]

实际应用案例[编辑 | 编辑源代码]

案例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语言编程能力,特别是在系统编程和性能敏感场景中。建议通过内存绘图加深理解。