代码示例: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 章展开)。 # # 一句可背的结论:指针运算与下标越界 = 未定义行为;标准不保证报错,也不保证"看起来正常"。