指针试题合集
前言
关于一部分指针的笔试题;向着星辰与深渊!
一、题目
题目一:
int main()
{
int a[5] = { 1, 2, 3, 4, 5 };
int *ptr = (int *)(&a + 1);
printf( "%d,%d", *(a + 1), *(ptr - 1));
return 0;
}
//程序的结果是什么?
数组名:表示首元素地址;但有两种例外;
sizeof(数组名)
:这里表示计算整个数组的大小,数组名表示整个数组地址;
&数组名
:取出整个数组的地址
首先*(a + 1)
a是首元素地址,a+1
是第二个元素地址解引用后是2;
题目中&a,取出整个数组的地址,加1跳过一个数组的大小,
&a+1
的地址放入int* ptr
,指针类型决定了操作权限,-1只能减一个int类型,所以指向5;
答案
2 5
题目二:
struct Test
{
int Num;
char *pcName;
short sDate;
char cha[2];
short sBa[4];
}*p = (struct Test*)0x100000;
//假设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;
}
p是变量,类型是结构体指针;
已知结构体类型变量类型是20字节;
p = 0x100000;
加1为跳过20字节,16进制20为14;
p + 0x1 = 0x100014;
unsigned long 无符号整形 p是0x100000,看做无符号整形加1后0x100001;
unsigned int* 是四个字节 0x100004
答案
0x100014
0x100001
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;
}
(&a+1)跳过一个数组大小,操作权限是int ,*(ptr1+(-1))所以000004,前面0不会打印;
a是首元素地址,把首元素地址看为int,+1就是原值+1,在看做int*
时,便是增加一个字节大小,又因为小端存储0x02000000,但是02前面的0不会显示;
答案
4,2000000
题目四:
#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;
}
这里看似和前几题相似,实则不然,如果把这个数组看成了
0 1
2 3
4 5
那就大错特错了
int a[3][2] = { {0, 1}, {2, 3}, {4, 5} };//这样初始化才这样
int a[3][2] = { (0, 1), (2, 3), (4, 5) };//看清楚这是小括号,是逗号表达式
实际上的初始化
1 3
4 0
0 0
a[0]是第一行元素, p[0] = 1
答案
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(*p)[4]
首先,p先和*相结合,所以这是个指针,是指向存放int型的有四个元素的数组的指针;
二维数组在内存中存放的其实是连续的,a是首元素地址;
指针的元素的类型,及确定了操作权限;
指针减指针代表的是元数个数;
如图显示,我们可以看到相差4个元素;
%p打印地址,%d按十进制输出
按%d打印-4;
在内存中存储的是补码,
原码:0000 0000 0000 0000 0000 0000 0000 0100
反码:1111 1111 1111 1111 1111 1111 1111 1011
补码:1111 1111 1111 1111 1111 1111 1111 1100
当地址打印时将补码看做地址输出,以16进制输出
FFFF FFFC
答案
FFFFFFFC,-4
题目六:
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的取出的是整个数组的地址,跳过整个二维数组;
*(ptr1-1) = 10;
aa是首元素地址,而二维数组的首元素是第一行元素,加1,跳过一行,ptr1操作一个整形。
*(ptr2-1) = 5;
答案
10,5
题目七:
#include <stdio.h>
int main()
{
char *a[] = {"work","at","alibaba"};
char**pa = a;
pa++;
printf("%s\n", *pa);
return 0;
}
char*
a[]
是数组,存放的是char*类型
所以,at
答案
at
题目八:
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;
}
先分析内存中布局是如何的?
首先:*++cpp
,cpp+1
后解引用
结果为POINT
*--*++cpp+3
先自增,解引用后–,在解引用后+3
找到ER
*cpp[-2]+3
等价于*(cpp+(-2))+3
找到ST
cpp[-1][-1]+1
等价于*(*(cpp+(-1))+(-1))+1
找到EW
答案
POINT
ER
ST
EW
总结
指针的坑,非常多,有限令人意想不到,就拿题目四来说,数组初始化用了逗号表达式,如果想都没想,那必然……;所以仔细分析,画图是个好方法。向着星辰与深渊!