C语言指针进阶(5):sizeof与strlen深度对比及笔试题全解
C语言指针进阶(5)sizeof与strlen深度对比及笔试题全解指针和数组是C语言笔试面试的高频考点而sizeof和strlen的区别更是重中之重。本文将通过大量经典笔试题详细解析一维数组、字符数组、二维数组在各种场景下的求值规则并深入剖析几道极具迷惑性的指针运算题目帮助读者彻底攻克指针难点。目录一、sizeof和strlen的对比二、数组和指针笔试题解析三、指针运算笔试题解析一、sizeof和strlen的对比特性sizeofstrlen本质操作符库函数需包含string.h功能计算变量/类型所占内存大小字节统计字符串长度\0之前的字符个数关注点不关心内存中存放的具体数据必须找到\0否则会越界查找示例sizeof(arr)计算整个数组大小strlen(arr)从起始地址向后数直到\0典型示例chararr1[3]{a,b,c};chararr2[]abc;printf(%d\n,strlen(arr1));// 随机值无\0printf(%d\n,strlen(arr2));// 3printf(%d\n,sizeof(arr1));// 3printf(%d\n,sizeof(arr2));// 4包含\0关键提醒sizeof计算数组时若数组名单独出现且无则代表整个数组strlen遇到\0才停止字符数组若没有手动添加\0则结果不可预测。二、数组和指针笔试题解析数组名规则回顾sizeof(数组名)— 数组名表示整个数组计算总大小。数组名— 数组名表示整个数组取出整个数组的地址。除此以外所有数组名均表示首元素地址。2.1 一维数组整型inta[]{1,2,3,4};printf(%d\n,sizeof(a));// 16整数组大小printf(%d\n,sizeof(a0));// 4/8a0 是首元素地址printf(%d\n,sizeof(*a));// 4*a 是首元素intprintf(%d\n,sizeof(a1));// 4/8第二个元素的地址printf(%d\n,sizeof(a[1]));// 4第二个元素printf(%d\n,sizeof(a));// 4/8整个数组的地址也是地址printf(%d\n,sizeof(*a));// 16*a 等价于 aprintf(%d\n,sizeof(a1));// 4/8跳过整个数组后的地址printf(%d\n,sizeof(a[0]));// 4/8首元素地址printf(%d\n,sizeof(a[0]1));// 4/8第二个元素地址2.2 字符数组代码1数组无\0chararr[]{a,b,c,d,e,f};printf(%d\n,sizeof(arr));// 6printf(%d\n,strlen(arr));// 随机值无\0代码2字符串初始化chararr[]abcdef;printf(%d\n,sizeof(arr));// 7含\0printf(%d\n,strlen(arr));// 6printf(%d\n,sizeof(*arr));// 1*arr 是 aprintf(%d\n,sizeof(arr1));// 4/8跳过整个数组的地址代码3指针指向常量字符串char*pabcdef;printf(%d\n,sizeof(p));// 4/8指针变量大小printf(%d\n,sizeof(p1));// 4/8地址printf(%d\n,sizeof(*p));// 1字符 aprintf(%d\n,strlen(p));// 6printf(%d\n,strlen(p1));// 5从 b 开始printf(%d\n,strlen(p));// 随机值p 是指针的地址不是字符串陷阱strlen(p)和strlen(p1)等传入的是指针变量的地址而非字符串起始地址结果随机。2.3 二维数组inta[3][4]{0};printf(%d\n,sizeof(a));// 483*4*4printf(%d\n,sizeof(a[0][0]));// 4printf(%d\n,sizeof(a[0]));// 16a[0] 是第一行数组名单独放 sizeof 代表整行printf(%d\n,sizeof(a[0]1));// 4/8a[0] 作为数组名未单独放降为第一行首元素地址1 是第二列地址printf(%d\n,sizeof(*(a[0]1)));// 4即 a[0][1]printf(%d\n,sizeof(a1));// 4/8a 是首行地址二维数组名非单独1 是第二行地址printf(%d\n,sizeof(*(a1)));// 16*(a1) 即 a[1] 整行数组printf(%d\n,sizeof(a[0]1));// 4/8a[0] 是第一行地址1 是第二行地址printf(%d\n,sizeof(*(a[0]1)));// 16解引用得第二行printf(%d\n,sizeof(*a));// 16*a 等价于 a[0]printf(%d\n,sizeof(a[3]));// 16虽然行下标越界但 sizeof 只评估类型a[3] 类型仍是 int[4]三、指针运算笔试题解析题目1a1与a1inta[5]{1,2,3,4,5};int*ptr(int*)(a1);printf(%d,%d,*(a1),*(ptr-1));// 输出2,5a1第二个元素地址解引用得 2。a1跳过整个数组5个int指向数组末尾再转为int*后-1指向最后一个元素 5。题目2结构体指针运算structTest{...}*p(structTest*)0x100000;printf(%p\n,p0x1);// 0x100014假设结构体20字节printf(%p\n,(unsignedlong)p0x1);// 0x100001整数1printf(%p\n,(unsignedint*)p0x1);// 0x100004int* 步长4题目3逗号表达式陷阱inta[3][2]{(0,1),(2,3),(4,5)};int*pa[0];printf(%d,p[0]);// 1注意圆括号内是逗号表达式值为最后一个表达式。所以(0,1)→1(2,3)→3(4,5)→5。实际初始化{{1,3},{5,0},{0,0}}a[0][0]1。题目4指针与数组下标inta[5][5];int(*p)[4];// 指向含4个int数组的指针pa;printf(%p,%d\n,p[4][2]-a[4][2],p[4][2]-a[4][2]);p[4][2]相当于*(*(p4)2)p步长为4*416字节而a步长5*420字节。二者差4个元素以int为单位输出-4十六进制FFFFFFFC。题目5二维数组地址intaa[2][5]{1,2,3,4,5,6,7,8,9,10};int*ptr1(int*)(aa1);int*ptr2(int*)(*(aa1));printf(%d,%d,*(ptr1-1),*(ptr2-1));// 输出10,5aa1跳过整个二维数组ptr1-1指向最后一个元素 10。*(aa1)是第二行数组aa[1]是第二行首元素地址ptr2-1指向第一行最后一个元素 5。题目6指针数组与二级指针char*a[]{work,at,alibaba};char**paa;pa;printf(%s\n,*pa);// at题目7多级指针与复杂表达式经典char*c[]{ENTER,NEW,POINT,FIRST};char**cp[]{c3,c2,c1,c};char***cppcp;printf(%s\n,**cpp);// 先 cpp 指向 cp[1]c2** 得 POINTprintf(%s\n,*--*cpp3);// 分析cpp 指向 cp[2]c1--*cpp 使 c1 变为 c再 * 得 ENTER3 → ERprintf(%s\n,*cpp[-2]3);// cpp 当前指向 cp[2]c1cpp[-2] cp[0]c3* 得 FIRST3 → STprintf(%s\n,cpp[-1][-1]1);// cpp[-1] cp[1]c2[-1] 得 c1再 1 得 EW关键这类题目需要画图逐步推导指针的指向变化理解、--的副作用及优先级。总结本文详细对比了sizeof与strlen的本质区别并通过大量笔试真题解析了一维、字符、二维数组在不同上下文中的求值规则以及多级指针的复杂运算。掌握这些题目背后的原理能够显著提升对C语言指针的理解深度轻松应对各类面试考题。建议读者动手逐题调试验证画出内存布局图真正做到融会贯通。