跳到主要内容
🔍

代码示例:1.3.2 指针与数组/字符串/多级指针

全部示例均标注编译命令、适用环境与实测状态;完整验证记录见《03.5-代码编译运行验证记录》。

  • examples/ex1-pointer-array.c · 指针与一维数组互操作(p[i] 与 *(p+i)、指针差、数组形参衰减)

    /* ex1-pointer-array.c —— 指针与一维数组互操作(1.3.2)
     * 适用环境:Linux / Windows(MinGW) 标准:C11
     * 编译:gcc ex1-pointer-array.c -o ex1 -std=c11 -Wall -Wextra -Wpedantic
     * 运行:./ex1(Windows: ex1.exe)
     */
    #include <stdio.h>
     
    static void print_array(const int *p, int n)
    {
        /* 数组形参退化为指针;p[i] 与 *(p+i) 等价 */
        for (int i = 0; i < n; i++) {
            printf("p[%d]=%d ", i, p[i]);
        }
        printf("\n");
    }
     
    int main(void)
    {
        int a[] = {10, 20, 30, 40, 50};
        int *p = a;                    /* 数组名转换为首元素地址 */
        printf("*p = %d, p[2] = %d, *(p+2) = %d\n", *p, p[2], *(p + 2));
        int *q = &a[3];
        printf("q - p = %lld(元素个数,3)\n", (long long)(q - p));
        printf("&a[1] == p+1 ? %s\n", (&a[1] == p + 1) ? "yes" : "no");
        print_array(a, 5);
        return 0;
    }
     
  • examples/ex2-array-pointer-pointer-array.c · 数组指针遍历二维数组 + 指针数组存字符串(sizeof 验证)

    /* ex2-array-pointer-pointer-array.c —— 数组指针与指针数组(1.3.2)
     * 适用环境:Linux / Windows(MinGW) 标准:C11
     * 编译:gcc ex2-array-pointer-pointer-array.c -o ex2 -std=c11 -Wall -Wextra -Wpedantic
     * 运行:./ex2(Windows: ex2.exe)
     */
    #include <stdio.h>
     
    int main(void)
    {
        int grid[2][3] = {{1, 2, 3}, {4, 5, 6}};
        int (*row)[3] = grid;          /* 数组指针:指向"3 个 int 的数组" */
        for (int i = 0; i < 2; i++) {
            for (int j = 0; j < 3; j++) {
                printf("%d ", row[i][j]);
            }
            printf("\n");
        }
        const char *names[] = {"linux", "driver", "bsp"};  /* 指针数组 */
        for (int i = 0; i < 3; i++) {
            printf("names[%d] = %s\n", i, names[i]);
        }
        printf("sizeof(names) = %zu(3 个指针)\n", sizeof(names));
        return 0;
    }
     
  • examples/ex3-argv.c · main(int argc, char **argv) 参数解析(含空格参数)

    /* ex3-argv.c —— main(int argc, char **argv) 参数解析(1.3.2)
     * 适用环境:Linux / Windows(MinGW) 标准:C11
     * 编译:gcc ex3-argv.c -o ex3 -std=c11 -Wall -Wextra -Wpedantic
     * 运行:./ex3 alpha beta "two words"(Windows: ex3.exe alpha beta "two words")
     */
    #include <stdio.h>
     
    int main(int argc, char **argv)
    {
        printf("argc = %d\n", argc);
        for (int i = 0; i < argc; i++) {
            printf("argv[%d] = %s\n", i, argv[i]);
        }
        return 0;
    }
     
  • examples/ex4-ub-notes.txt · 指针越界与跨数组运算是未定义行为(conceptual:静态讲解,不运行)

    # 1.3.2 越界与跨数组指针运算:未定义行为(conceptual 讲解,不编译不运行)
    # 本文件是"概念讲解型"示例(example_kind=conceptual):只引语言标准,不执行任何越界代码。
    #
    # 为什么本章不运行越界演示?
    # C 标准(ISO/IEC 9899:2011)规定:
    #   - J.2 未定义行为清单:数组下标越界;
    #   - 6.5.6p8:指针与整数相加,结果必须仍指向同一数组对象的元素或"尾后一个位置",否则未定义;
    #   - 6.5.8p5:指向不同数组对象的两个指针做关系比较,行为未定义(同一数组内才可比较)。
    # 未定义行为的含义:标准对结果不做任何保证——可能读到垃圾、可能"看起来正常"、
    # 可能崩溃、可能破坏相邻数据;不同编译器/优化级别结果不同。
    # 因此"跑一次越界程序观察输出"得不到可依赖的规律(违反本课程"不依赖偶然行为"的纪律)。
    #
    # 正确学习方式:
    # 1. 遍历用边界条件:int a[n],合法下标 0..n-1,指针范围 [a, a+n);
    # 2. 指针差(q-p)只在同一数组内才有意义,结果是元素个数;
    # 3. 数组指针 p+1 步长是"整个所指数组"(sizeof(*p) 验证),不要手动乘字节数;
    # 4. 运行时防御预告:AddressSanitizer(-fsanitize=address)能在多数实现上捕获越界读写(5.6 章展开)。
    #
    # 一句可背的结论:指针运算与下标越界 = 未定义行为;标准不保证报错,也不保证"看起来正常"。