文章目录
- 笔试题1
- 笔试题2
- 笔试题3
- 笔试题4
- 笔试题5
- 笔试题6
- 笔试题7
- 笔试题8
笔试题1
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,其有5个元素每个元素为int型。接着&a(取出的是整个数组a的地址,因为&数组名
取出的是整个数组的地址),然后+1(跳过一整个数组,也就是数组a,地址指向数组末尾的位置;原因是:地址(指针)的类型的决定了加减整数时的步长),最后将这个地址强制类型转化为int*
,再赋值给int* ptr
。内存布局如下图所示:
所以*(a + 1)
就是在访问数组a第二个元素,也就是这里的2;*(ptr - 1)
就是在访问数组a第五个元素,也就是这里的5(因为地址(指针)的类型决定了其在解引用操作的时候能过访问空间的大小,即:int型指针解引用访问int型大小的空间,char型指针解引用访问char型大小的空间)。故printf打印的及如果为2,5
。
笔试题2
//已知,结构体Test的类型大小是20个字节,假设p 的值为0x100000。
//问:如下表表达式的值分别为多少?
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;
}
首先创建了一个结构体类型Test,然后用该结构体类型定义了的指针变量p,并初始化为0x100000(也就是使指针p指向了地址为0x100000的内存空间)。接着调用主函数:
第一个printf:打印的是p + 0x1
的地址,也就是p+1
的地址(因为这里的0x1表示的是十六进制的1,转化为十进制也是1)。由于p是一个指向Test类型结构体的指针,所以+1就是跳过一个该类型结构体的大小,也就是20个字节,故打印结果为0x100000 + 20 = 0x100014
。
第二个printf:打印的是(unsigned long)p + 0x1
,运算顺序是先将指针强制类型转化为unsigned long
类型,也就是无符号长整形,那对整型+1不就仅仅只是加一嘛。故表达式(unsigned long)p + 0x1
的结果为0x100001
,然后printf以地址类型打印整型类型的0x100001,结果为:0x100001
。
第三个printf:打印的是(unsigned int*)p + 0x1
,与之前一样先强制类型转化unsigned int*
(注意:这可是一个指针类型啊,加减整数可不仅仅只是加减整数),所以这里的p+1其实是跳过了一个int型的大小,也就是4个字节。故打印结果为:0x100000 + 4 = 0x100004
。
笔试题3
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;
}
//问:打印结果是什么?
首先创建了一个int [4]
型的数组,然后为int*
类型的指针ptr1和ptr2赋值,其中int *ptr1 = (int *)(&a + 1);
与笔试1类似,指向的是数组a的末尾。这道题主要考点这于(int *)((int)a + 1)
,它先是将a强制类型转化为int型,也就是将数组a首元素的地址强制类型转化为int型,当成整型来看(因为数组名一般情况下表示数组首元素的地址)。然后对其+1,自然结果仅仅就是加一,然后将得到的这个整型数强制类型转化为(int*)
后赋值给pt2,故此时ptr2指向的就是数组首元素地址向后跳一个字节后的空间。内存布局如下图所示:
最后打印ptr1[-1]
等价于*(ptr-1)
,printf是以%x(十六进制)的形式打印,所以最后的结果为:4,2000000
。
笔试题4
int main()
{
int a[3][2] = { (0, 1), (2, 3), (4, 5) };
int *p;
p = a[0];
printf( "%d", p[0]);
return 0;
}
//问:最后打印结果是什么?
首先定义了一个3行2列的二维数组,然后对其初始化{ (0, 1), (2, 3), (4, 5) }
,大家有没有觉得很变扭,初始化二维数组什么时候用()啦?不因该是{ {0, 1}, {2, 3}, {4, 5} }
这样嘛。所以这里的()并不是代表一行,而因该是逗号表达式,故这里的初始化因该是不完全初始化,内存布局如下图所示:
接着将p = a[0];
,其中a[0]表示的数组a第一行的数组名,而数组名又表示数组首元素的地址,故这里的a[0]表示第一行首元素的地址,即a[0][0]的地址。然后printf打印p[0],结果为1。
笔试题5
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;
}
//问:最后打印结果是什么?
首先创建了一个5行5列的二维数组a,然后又创建了一个数组指针p(其指向的数组有4个元素,每个元素都是int型的)。我们有知道二维数组的数组名本质上表示的是第一行的地址,p = a;
就是将二维数组a第一行的地址赋值给了数组指针p(注意:虽然它两的类型不同,但传递的值是不变的),故你会发现此时a和p指向了同一个位置。
其实我们完全可以把p和a都看成二维数组(只不过这两个二维数组的起始位置是相同的,而且p代表的二维数组每行只有4个元素,而a代表的每行却有5个元素)。然后来理解 &p[4][2] - &a[4][2]
,这求的不就是两个地址之间元素的个数嘛(因为指针 ‘-’ 指针的值是,指针之间元素的个数),而且是二维数组p第4行第2列元素地址与二维数组a第4行第2列元素地址之间元素的个数,那不就只要知道p[4][2]
前元素的个数和a[4][2]
前元素的个数之后相减就可以得到想要的结果了(注意:指针‘-’指针的值也可能会是负数)。p[4][2]
前元素的个数是4 * 4 + 2 = 18
,a[4][2]
前元素的个数是4 * 5 + 2 = 22
,故&p[4][2] - &a[4][2]
的结果为 -4 。内存布局如下图所示:
然而这道题还没有做完,他还考了一个知识点,printf是要以两种不同的形式分别输出&p[4][2] - &a[4][2]
表达式的结果。我们知道%d表示是以有符号整型输出,故输出因该是:-4。而%p是专门用来打印地址的(而且是十六进制形式输出),但我们要知道地址在存放的时候可没有原码、反码、补码这么一说,它是直接放入内存当中的,故取的时候也直接取就完事了,不需要经过任何的转换(即内存当中是什么,打印的就是什么)。打印结果就是-4的补码,即:ff ff ff fc。
笔试题6
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;
}
//问:最后打印结果是什么?
首先创建了一个2行5列的二维数组aa,然后你会发现这题的考点其实与之例题3的考点差不多。只不过是将一维数组的数组名换成了二维数组的数组名罢了。下面看内存布局:
笔试题7
int main()
{
char* a[] = { "work","at","alibaba" };
char** pa = a;
pa++;
printf("%s\n", *pa);
return 0;
}
//问:最后打印结果是什么?
首先创建了一个字符指针数组,然后使每一个字符指针都指向一个常量字符串,接着创建了一个二级指针pa,让其指向指针数组a首元素a[0]。内存布局如下图所示:
*pa访问的是a[1],而a[1]中存放的是字符串“at”首字符a的地址,所以printf打印的结果是“at”。
笔试题8
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;
}
//问:最后打印结果是什么?
关于这道题大家就不要吝啬你的草稿纸了,内存布局画出来分析吧,不然光靠想是做不出来的,因为太过于混乱了。内存布局如下图所示:
接下来就是简单的根据表达式的优先级的运算,来最终求出打印的结果。
这份博客👍如果对你有帮助,给博主一个免费的点赞以示鼓励欢迎各位🔎点赞👍评论收藏⭐️,谢谢!!!
如果有什么疑问或不同的见解,欢迎评论区留言欧👀。