跳转到内容

C 语言指针与数组

来自代码酷

C语言指针与数组[编辑 | 编辑源代码]

介绍[编辑 | 编辑源代码]

在C语言中,指针数组是紧密相关的概念。指针是存储内存地址的变量,而数组是连续内存中存储的相同类型元素的集合。理解它们的关系对高效操作内存、字符串处理和动态数据结构至关重要。本章将详细讲解指针如何与数组交互,并通过示例展示实际应用。

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

数组名在大多数情况下会被编译器转换为指向其首元素的指针。例如,若声明一个数组 int arr[5],则 arr 等价于 &arr[0](即第一个元素的地址)。这种特性使得指针可以像数组一样通过下标访问元素。

代码示例:指针与数组的等价性[编辑 | 编辑源代码]

#include <stdio.h>

int main() {
    int arr[3] = {10, 20, 30};
    int *ptr = arr; // ptr指向数组首元素

    printf("arr[1] = %d\n", arr[1]);   // 输出20
    printf("ptr[1] = %d\n", ptr[1]);   // 同上,通过指针访问
    printf("*(ptr + 1) = %d\n", *(ptr + 1)); // 指针算术运算
    return 0;
}

输出:

arr[1] = 20
ptr[1] = 20
*(ptr + 1) = 20

解释:

  • ptr[1] 等价于 *(ptr + 1),即通过指针算术访问第二个元素。
  • 数组下标操作本质上是“语法糖”,底层仍通过指针算术实现。

指针算术与数组遍历[编辑 | 编辑源代码]

指针算术允许通过对指针加减整数来移动内存地址。步长由指针类型决定(如 int* 的步长为 sizeof(int))。

代码示例:指针遍历数组[编辑 | 编辑源代码]

#include <stdio.h>

int main() {
    float values[4] = {1.1, 2.2, 3.3, 4.4};
    float *p = values;

    for (int i = 0; i < 4; i++) {
        printf("values[%d] = %.1f\n", i, *(p + i));
    }
    return 0;
}

输出:

values[0] = 1.1
values[1] = 2.2
values[2] = 3.3
values[3] = 4.4

多维数组与指针[编辑 | 编辑源代码]

多维数组(如二维数组)在内存中仍按连续顺序存储,但需要通过多级指针或数组指针访问。

代码示例:二维数组与指针[编辑 | 编辑源代码]

#include <stdio.h>

int main() {
    int matrix[2][3] = {{1, 2, 3}, {4, 5, 6}};
    int (*ptr)[3] = matrix; // 指向包含3个元素的数组的指针

    printf("matrix[1][2] = %d\n", ptr[1][2]); // 输出6
    return 0;
}

解释:

  • int (*ptr)[3] 声明了一个指向包含3个整数的数组的指针。
  • ptr[1][2] 等价于 *(*(ptr + 1) + 2)

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

案例1:字符串处理[编辑 | 编辑源代码]

C语言中字符串是字符数组,常用指针操作:

#include <stdio.h>

void reverse_string(char *str) {
    char *end = str;
    while (*end) end++; // 找到字符串结尾
    end--; // 跳过空字符

    while (str < end) {
        char temp = *str;
        *str++ = *end;
        *end-- = temp;
    }
}

int main() {
    char s[] = "hello";
    reverse_string(s);
    printf("%s\n", s); // 输出 "olleh"
    return 0;
}

案例2:动态数组[编辑 | 编辑源代码]

通过指针和动态内存分配实现灵活数组:

#include <stdio.h>
#include <stdlib.h>

int main() {
    int *dynamic_arr = malloc(5 * sizeof(int)); // 动态分配5个int
    for (int i = 0; i < 5; i++) {
        dynamic_arr[i] = i * 10;
    }
    free(dynamic_arr); // 释放内存
    return 0;
}

常见误区与注意事项[编辑 | 编辑源代码]

1. 数组名不是指针:尽管可以转换为指针,但 sizeof(arr) 返回数组总大小,而 sizeof(ptr) 返回指针大小。 2. 指针越界:访问超出数组范围的指针会导致未定义行为。 3. 数组衰减:函数传递数组时,数组会退化为指针,丢失长度信息。

总结[编辑 | 编辑源代码]

指针与数组的关系是C语言的核心特性之一,理解它们的交互能提升代码效率和灵活性。关键点包括:

  • 数组名作为指针使用时的隐式转换。
  • 指针算术对数组遍历的优化。
  • 多维数组的指针表示法。
  • 动态内存管理与指针的结合。

graph LR A[指针] --> B[存储地址] C[数组] --> D[连续内存块] B --> E[通过算术访问元素] D --> E

通过实践和调试,读者可以逐步掌握这些概念,并应用于更复杂的数据结构中。