题型1:二维数组初始化 + 逗号表达式陷阱(最高频坑!)
代码:
int a[3][2] = { (0, 1), (2, 3), (4, 5) };
int* p;
p = a[0];//*(a+0) 本来串的是第一行元素, a会退化成首元素地址
printf(“%d”, p[0]);
✅ 考点: () 里面是逗号运算符,不是行分组!逗号表达式只保留最右侧值
(0,1) → 结果是 1 ; (2,3) → 3 ; (4,5) → 5
内存填充: a[3][2] = {1,3,5,0,0,0} //剩余的填充0进去
输出: 1
❌ 误区:误以为 (0,1) 是一行两个元素(只有 {} 才是分组)
int a[3][2]={{0,1},{2,3},{4,5}};这个才是分组
题型2:数组指针 + 指针减法(求元素个数,不是字节差)
int a[5][5];
int (*p)[5]; // 数组指针:一步跨过一整行5个int
p = a;
printf(“%d, %d”, &p[4][2] - &a[4][2], &p[4][2] - &a[2][2]);
答案:0 10
每一行有5个元素,然后它跳过了两行,一共10个元素。
✅ 考点:
- 同类型指针相减,结果 = 中间相隔元素数量,不是字节
- int ()[5] 步长: 5sizeof(int) ; int* 步长:1个int
重点:小地址 - 大地址 → 负数
题型3:二维数组 + &aa+1 / *aa+1 区分(必考)
c
int aa[2][5] = {1,2,3,4,5,6,7,8,9,10};
int* ptr1 = (int*)(&aa + 1);
int* ptr2 = (int*)(*(aa + 1));
printf(“%d,%d”, *(ptr1 - 1), *(ptr2 - 1));
✅ 考点拆分:
- &aa :整个二维数组的地址,类型 int (*)[2][5] ; &aa+1 直接跳过整个二维数组
- aa 是数组名, aa+1 :数组指针,跳过一行(5个int)
输出: 10,5
题型4:三级指针 char*** 多级指针链式解引用(你那个ENTER/NEW题)
c
char* c[] = { “ENTER”,“NEW”,“POINT”,“FIRST” };
char** cp[] = { c + 3, c + 2, c + 1, c };
char*** cpp = cp;
printf(“%s\n”, ***cpp);
printf(“%s\n”, * ++cpp + 3);
printf(“%s\n”, *cpp[-2] + 3);
printf(“%s\n”, cpp[-1][-1] + 1);
先 画图:
c enter new point first
cp first point new enter
cpp =cp[0]=c[3] printf(“frist”);
*(++cpp)= cp[1] =c[2] point ->3 printf(“nt”);
cpp[-2] =cp[-1]=c[3] frist->printf(“st”);
cpp[-1][-1] = ((cpp-1)-1)+1=(c+3-1)+1=oint
✅ 考点:
- 运算符优先级: ++/-- > * > +
- cpp[i] 等价 *(cpp+i) ;多层解引用逐层降一级指针
- char* + n :在字符串内部向后跳字母(步长1字节)
- char** + n :跳到下一个字符串首地址(步长是地址宽度)
核心口诀:解引用降一层;什么类型指针,+1就跳这个类型的大小
题型5:char*指针数组,指针自增
c
char* a[] = {“work”,“at”,“alibaba”};
char** pa = a;
pa++;
printf(“%s\n”, *pa);
✅ 考点: pa 是 char** ,pa++ 跳过一个 char* ,指向第二个字符串
输出: at
题型6:结构体指针 + 指针步长(强制转换指针,步长由类型决定)
c
struct Test
{
int Num;
char* pcName;
short sDate;
char cha[2];
short sBa[4];
}p;
// 题目给定:结构体大小20字节
p = (struct Test)0x100000;
printf(“%p\n”, p + 0x1);
printf(“%p\n”, (unsigned long)p + 0x1);
printf(“%p\n”, (unsigned int*)p + 0x1);
✅ 考点(超级重要):
- p + 1 :结构体指针,+1 跳整个结构体大小20字节,转16进制后是014
- 转成普通整数 unsigned long 再加1:只+1个字节
- unsigned int* 指针+1:跳4字节
本质:指针加法的步长,完全由指针本身的类型决定,和原始地址无关
配套通用考点笔记
- ✅ 数组名什么时候不退化: sizeof(数组名) 、 &数组名 ;其余全部退化成首元素指针
- ✅ 指针减法硬性规则:必须指向同一块连续内存,结果是元素个数,不是字节;小地址减大地址为负
- ✅ 逗号表达式: (a,b,c) ,顺序执行a→b→c,整个表达式的值 = 最右边c的值;只有 () 里逗号才是逗号运算符, {} 里面逗号只是分隔符!(本题最大坑)
- ✅ 多级指针分层:
- char* → 存字符串首地址,+1跳1个字符
- char** → 存 char* 的地址,+1跳一个字符串指针
- char*** → 存 char** 的地址,+1跳一个char**
- ✅ [] 等价: p[i] == *(p+i) ,正负下标都合法(只要内存有效,考试随便考负数下标)
刷题顺序建议
- 先搞定【逗号表达式二维数组初始化】(最容易掉坑)
- 然后 &aa+1 vs aa+1 二维数组行指针题(aa为二维数组,实际为int()[],+1就直接跳到下一行了)
- 结构体指针步长(很多人分不清强制转换之后步长变了)
- 三级指针链式解引用(ENTER那道,运算符优先级地狱题)
- 指针减法+补码(负数地址打印)
本文系统总结C语言指针六大高频题型:二维数组逗号表达式初始化陷阱、数组指针与指针减法求元素个数、&数组名+1与数组名+1的语义差异、三级指针链式解引用与运算符优先级、指针数组自增行为、结构体指针强制转换后的步长规则。重点强调指针类型决定算术步长、同类型指针相减得元素数、逗号表达式值为最右操作数等核心机制,覆盖sizeof和&不退化、多级指针降级解引用等关键考点。
264

被折叠的 条评论
为什么被折叠?



