上一篇我们也介绍了指针的笔试题,这一篇我们趁热打铁继续讲解8道指针更有趣的笔试题,,让大家更加深刻了解指针,从而也拿下【C语言】指针这个难点!
本次解析是在x86(32位)平台下进行
- sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。
- &数组名,这里的数组名表示整个数组,取出的是整个数组的地址。
- 除此之外所有的数组名都表示首元素的地址。
- 指针关系运算
以下代码结果是什么!?
int main()
{
int a[5] = { 1, 2, 3, 4, 5 };
int *ptr = (int *)(&a + 1);
printf( "%d,%d", *(a + 1), *(ptr - 1));
return 0;
}
//程序的结果是什么?
解析:
int *ptr = (int *)(&a + 1); (&a = int( *)[5]) &a取出了整个数组地址,&a+1跳过整个数组(ptr并没有解引用,所以不会造成越界访问)
*(a + 1) ,a是数组名,数组名代表首元素地址,首元素地址+1,跳到下一个元素2的地址,在解引用。 第一个输出结果答案是->2
*(ptr - 1),ptr此时指向了组最后一个元素地址的下一个地址, -1又回到了最后一个元素地址,解引用。第二个输出结果答案是->5
以下代码结果是什么!?
struct Test
{
int Num;
char *pcName;
short sDate;
char cha[2];
short sBa[4];
}*p;
假设p 的值为0x100000。 如下表表达式的值分别为多少?
已知,结构体Test类型的变量大小是20个字节
int main()
{
printf("%p\n", p + 0x1);
printf("%p\n", (unsigned long)p + 0x1);
printf("%p\n", (unsigned int*)p + 0x1);
return 0;
}
解析:
0x1 就是十六进制 1
printf(“%p\n”, p + 0x1);
p是一个结构体指针类型,结构体类型+1 跳过一个结构体大小,单位是字节。
所以p+1跳过20个字节,答案是-> 0x100014 .(十六进制14 代表十进制20)printf(“%p\n”, (unsigned long)p + 0x1);
p 强制类型转换成(无符号整形),整型+1就是+1.
所以整型p+1跳过一个字节 .答案是->0x100001printf(“%p\n”, (unsigned int*)p + 0x1);
p 强制类型转换成(整型指针类型),整型int指针+1,跳过一个整型。
答案是->0x100004
以下代码结果是什么!?
int main()
{
int a[4] = { 1, 2, 3, 4 };
int *ptr1 = (int *)(&a + 1);
int *ptr2 = (int *)((int)a + 1);
printf( "%x,%x", ptr1[-1], *ptr2);
return 0;
}
代码可能在x64位平台下编译不过 ,请换成x86(32)位平台
解析:
int *ptr1 = (int *)(&a + 1);
&a取出整个数组的地址,+1跳过整个数组int *ptr2 = (int *)((int)a + 1);
a强制类型转换成 (整型),整型+1就是+1,跳过一个字节printf( “%x,%x”, ptr1[-1], *ptr2);
图析:所以ptr1[-1]答案->是 4
*ptr2 答案是-> 02 00 00 00
以下代码结果是什么!?
#include
int main()
{
int a[3][2] = { (0, 1), (2, 3), (4, 5) };
int *p;
p = a[0];
printf( "%d", p[0]);
return 0;
}
解析:
大家看清楚了! {}括号里面的()是逗号表达式,逗号表达式只算最后一个元素,所以int a【3】【2】 实际放的是 {1,3,5,0,0,0}
p = a[0] p是一个指针变量,a【0】 (a没有单独放在sizoef内部,代表的是二维数组首元素地址,二维数组首元素是第一行的地址, 那a是第一行了,a[0] 又是 第一行第一个元素a【0】【0】)。
所以 p[0] 是第一个元素,答案是->1
以下代码结果是什么!?
int main()
{
int a[5][5];
int(*p)[4];
p = a;
printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
return 0;
}
解析:
以下代码结果是什么!?
int main()
{
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));
return 0;
}
解析:
int *ptr1 = (int *)(&aa + 1);
&aa取出整个数组的地址,+1跳过aa数组,来到10元素后面的位置。int * ptr2 = (int *)( *(aa + 1));
aa代表首元素地址(二维数组首元素地址是第一行地址),首元素地址+1就是第二个行的地址,在解引用。*(ptr1 - 1)
ptr1-1 指向了元素10(&a[1][4])的地址, 解引用找到10,答案是->10*(ptr2 - 1)
ptr2-1 指向了后面5(&a[0][4])的地址,在解引用。答案是->5
以下代码结果是什么!?
#include
int main()
{
char *a[] = {"work","at","alibaba"};
char**pa = a;
pa++;
printf("%s\n", *pa);
return 0;
}
解析:
*pa
以下代码结果是什么!?
int main()
{
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);
return 0;
}
该题比较复杂,要先画出内存部图才分析,不然很难做对
解析:
printf(“%s\n”, * * ++cpp);
printf(“%s\n”, * - - * ++cpp+3);
printf(“%s\n”, *cpp[-2]+3);
cpp[-2] = * (cpp-2)
printf(“%s\n”, cpp[-1][-1]+1);
cpp[-1][-1] = *( *(cpp-1)-1)
完!
把二维数组当成一维数组来看待。题目就没有那么抽象
指针类型加减运算决定了,对指针解引用的时候有多大的权限(能操作几个字节)
如果不是单独放在sizeof()内部,一般的操作都会使指针降一阶
对于抽象的指针一定要画图理解,不然很难做出。