数组与指针

翻译整理自 cppreference - 数组 与 指针。

1. 一维数组

int arr[5] = {1, 2, 3, 4, 5};
int b[5]   = {0};              // 全 0
int c[5]   = {1, 2};           // 1,2,0,0,0
int d[]    = {1, 2, 3};        // 大小推断为 3

获取长度:

int n = sizeof(arr) / sizeof(arr[0]);

2. 多维数组

int m[2][3] = {
    {1, 2, 3},
    {4, 5, 6}
};

m[1][2] = 99;

for (int i = 0; i < 2; i++)
    for (int j = 0; j < 3; j++)
        printf("%d ", m[i][j]);

3. 指针基础

int x = 10;
int *p = &x;             // 取地址

printf("%p\n", (void *)p);
printf("%d\n", *p);      // 解引用,10
*p = 20;
printf("%d\n", x);       // 20

4. 指针与数组

数组名在表达式中退化为指向首元素的指针:

int arr[5] = {1, 2, 3, 4, 5};
int *p = arr;            // 等价 p = &arr[0]
printf("%d\n", p[2]);    // 3
printf("%d\n", *(p + 2));// 3

5. 指针算术

int *p = arr;
p++;                     // 移动到下一元素(地址 + sizeof(int))
p + 2;
p - 1;
p2 - p;                  // 元素个数差

6. 字符串与字符指针

char s[] = "hello";      // 数组,可改
char *t  = "hello";      // 字符串字面量,**只读**
s[0] = 'H';              // OK
t[0] = 'H';              // UB! 修改只读内存

改字符串用数组,避免用 char * 指向字面量后修改。

7. const 与指针

const int *p1;           // 指向 const int 的指针,不能 *p1 = ..
int *const p2 = &x;      // 指针本身 const,不能 p2 = ..
const int *const p3 = &x; // 都 const

阅读技巧:从右往左读。

8. 指针的指针

int x = 5;
int *p = &x;
int **pp = &p;

**pp = 10;
printf("%d\n", x);       // 10

9. 动态分配内存

malloc / calloc / realloc / free:

#include <stdlib.h>

int *arr = malloc(10 * sizeof(int));
if (!arr) { perror("malloc"); exit(1); }

for (int i = 0; i < 10; i++) arr[i] = i;

arr = realloc(arr, 20 * sizeof(int));   // 扩容

free(arr);                                // 别忘释放
arr = NULL;                               // 防悬空

calloc 自动清零:

int *z = calloc(10, sizeof(int));

10. 函数指针与回调

void apply(int *arr, int n, int (*fn)(int)) {
    for (int i = 0; i < n; i++) arr[i] = fn(arr[i]);
}

int dbl(int x) { return x * 2; }

apply(arr, 5, dbl);

11. 数组指针 vs 指针数组

int *arr1[10];              // 指针数组:10 个 int*
int (*arr2)[10];            // 数组指针:指向含 10 个 int 的数组

12. 常见陷阱

  • 越界访问:arr[5] 当 arr 只有 5 个元素
  • 悬空指针:free 后继续用
  • 内存泄漏:分配后忘记 free
  • 二次释放:同一指针 free 两次
  • 返回局部变量地址

小结

指针是 C 的灵魂也是危险之源,下一章学习字符串。