欢迎来CILMY23的博客喔,本期系列为【C语言】指针练习篇(下),深入理解指针---指针练习题【图文讲解,详细解答】,图文讲解指针练习题,带大家更深刻理解指针的应用,感谢观看,支持的可以给个赞哇。
前言
作为指针系列的番外练习篇,本篇主要以指针练习题为主,本期博客将上期未写的二维数组开头,并且以做题的视角带入,进行深刻理解指针练习题中不同用法区别。
二、指针,数组笔试题
2.3二维数组
int a[3][4] = { 0 };printf("%d\n", sizeof(a));printf("%d\n", sizeof(a[0][0]));printf("%d\n", sizeof(a[0]));printf("%d\n", sizeof(a[0] + 1));printf("%d\n", sizeof(*(a[0] + 1)));printf("%d\n", sizeof(a + 1));printf("%d\n", sizeof(*(a + 1)));printf("%d\n", sizeof(&a[0] + 1));printf("%d\n", sizeof(*(&a[0] + 1)));printf("%d\n", sizeof(*a));printf("%d\n", sizeof(a[3]));
x86环境结果如下:
x64环境结果如下:
2.3解析:
printf("%d\n", sizeof(a));
a单独放在sizeof后面,计算的是整个数组的大小,大小3*4*4 = 48字节
printf("%d\n", sizeof(a[0][0]));a [0][0],表示的是数组第1行第1列元素,元素是0,计算大小是整型,大小为4字节
printf("%d\n", sizeof(a[0]));a[0] 表示的是数组第一行的数组名,单独放在sizeof后面,计算的是一个一维数组的大小,大小为4*4 = 16字节
printf("%d\n", sizeof(a[0] + 1));a[0] 表示的是数组第一行的数组名,因为并没有单独放在sizeof后面,所以数组名表示数组首元素的地址,也就是a[0][0]的地址, a[0] + 1 == *(a+0) + 1 是第一行第二个元素的地址,是地址,大小就为4/8字节
printf("%d\n", sizeof(*(a[0] + 1)));根据上面解释,解引用后得到的解释第一行第二个元素,数据类型是整型,所以大小为4字节
printf("%d\n", sizeof(a + 1));a并没有单独放在sizeof后面,没有&,所以表示数组首元素的地址,即a[0],+1后就表示a[1]的地址,是地址就为4/8字节
printf("%d\n", sizeof(*(a + 1)));根据上面所说,得到的就是a[1]所对应的元素,计算的是整个一维数组的大小,数据类型是int,所以大小为4*4 = 16字节
printf("%d\n", sizeof(&a[0] + 1));&a[0]表示将第一行的数组地址取出来,+1就是跳过整个数组,表示的是a[1]的地址,是地址大小为4/8字节
printf("%d\n", sizeof(*(&a[0] + 1)));同上所述,解引用后计算的是a[1]整个数组的大小,大小为4*4=16字节
printf("%d\n", sizeof(*a));a是数组首元素的地址,也就是数组第一行(a[0])的地址,解引用计算的是 a[0],计算的是一个一维数组的大小,大小为4*4 = 16。
*a == *(a+0) == a[0]
printf("%d\n", sizeof(a[3]));因为sizeof是根据类型推断的,所以它不会实际访问,在这里a[3] == a[0],所以大小为4*4 = 16
三、指针运算笔试题
3.1
#include<stdio.h>int main()
{int a[5] = { 1, 2, 3, 4, 5 };int* ptr = (int*)(&a + 1); printf("%d,%d", *(a + 1), *(ptr - 1));return 0;
}
结果如下:
解析:
&a 表示取出整个数组的地址,+1后表示指向五后面的地址,将其整体转换成int *类型存入,ptr指针变量中,所以ptr此刻指向的是五的末尾,(a+1),a是数组名,并没有单独放在sizeof后面,也没有&操作符,所以表示数组首元素地址,+1指向数组第二个元素的地址,解引用得到2,ptr - 1,跳过的是指针类型,ptr的指针类型是int * 类型,所以跳过4个字节,指向五的前面,解引用得到5,所以答案为2,5
3.2
#include<stdio.h>
//在X86环境下
//假设结构体的⼤⼩是20个字节
//程序输出的结构是啥?
struct Test
{int Num;char* pcName; short sDate; char cha[2];short sBa[4];}*p = (struct Test*)0x100000;int main()
{printf("%p\n", p + 0x1);printf("%p\n", (unsigned long)p + 0x1); printf("%p\n", (unsigned int*)p + 0x1); return 0;
}
结果:
解析:考点是指针加减整数,不懂的可以看入门篇http://t.csdnimg.cn/n6szR
第一个,p+0x1 ,首先0x1,转换成十进制是加1,p是指针变量,加一跳过一个指针类型的大小,p的指针类型是结构体类型,大小为20,故答案是0x100014(原先的十六进制加二十)
第二个, p不是指针,所以p如果加1,就是简单的值相加,故原先的十六进制加1,答案为0x100001
第三个,p是unsigned int*类型的指针变量,指针变量+1,跳过一个unsigned int*类型大小,故加4,0x100004
3.3
#include <stdio.h>
int main()
{int a[3][2] = { (0, 1), (2, 3), (4, 5) }; int* p;p = a[0];printf("%d", p[0]);return 0;
}
解析:
因为数组中是有逗号表达式,所以从左到右依次计算,但是整个表达式的结果是最后一个一个表达式的结果,故数组中的值是{1,3,5};
所以 int a[3][2] = { 1,3,5}
所以打印结果为1
3.4
//假设环境是x86环境,程序输出的结果是啥?
#include <stdio.h>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;}
结果如下:
解析:考点为指针减指针,不懂的可以看入门篇http://t.csdnimg.cn/n6szR
int (*p)[4]是一个数组指针,如果把a放入p中,就相当于用p给a数组划分区域了。
它们中间相差四个元素,相减完得到-4.
如果用%p打印-4,就打印地址,就是用二进制表示-4,%d就是直接打印-4
FFFFFFFC,-4
3.5
#include <stdio.h>
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;
}
结果如下:
解析:
&aa + 1,aa是数组名,放在&后面,表示取出整个数组的地址,+1表示指向10的末尾的地址,将其转换成int * 类型,放入ptr1
(aa + 1) aa是数组名,没有单独放在sizeof后面,也没有&操作符,所以表示数组首元素地址,aa[0]. +1后表示a[1]的地址。将其解引用后,就表示a[1]。将其存入ptr2 减一后指向的位置就是5.
所以答案就为10和5
aa分布图如下:
3.6
#include <stdio.h>
int main()
{char* a[] = { "work","at","alibaba" }; char** pa = a;pa++;printf("%s\n", *pa); return 0;
}
结果如下:
解析:
char* a[] 是一个指针数组,当中存放的是w a a的地址,我们用一个二级指针pa来指向a这个数组,pa++后指向的是中间区域,解引用后得到的就是at
3.7
#include <stdio.h>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);
**++cpp,此刻cpp先加后用,cpp指向cp的第二个元素,也就是c+2的位置,解引用第一层,获得p的地址,再解引用后,得到POINT
printf("%s\n", *-- * ++cpp + 3);
* -- *++ cpp + 3 首先看++cpp,指向C+2这个位置,++cpp后,指向c+1这个位置,解引用后,再--,指向E这个位置,解引用后+3,指向的是T后面E前面,所以打印ER
printf("%s\n", *cpp[-2] + 3);
cpp[-2] == *(cpp-2),所以此刻cpp指向的位置是C+3,解引用后得到F所指向的位置,+3后指向S的前面,最后打印,得到ST
printf("%s\n", cpp[-1][-1] + 1);cpp[-1][-1] === *(*(cpp -1) -1), cpp指向的位置是c+1,减一后指向c+2,解引用后指向p,然后减一,指向N,最后解引用再+1,指向E前面,所以打印EW
图如下所示
感谢各位同伴的支持,本期指针练习篇(下)就讲解到这啦,如果你觉得写的不错的话,可以给个赞,若有不足,欢迎各位在评论区讨论。