指针八大经典题目

在此,我们将讲述C语言的精髓——指针的八道经典题目,这里我们主要以画图的方式解答。

提前说明:二维数组我们可以想象成由几个简单的一维数组组成。

题目一:

int main()
{
    int a[5] = { 1, 2, 3, 4, 5 };
    int *ptr = (int *)(&a + 1);
    printf("%d,%d", *(a + 1), *(ptr - 1));
    //2,5
    system("pause");
    return 0;
}

题目分析:数组名a表示数组首元素的地址,(&a+1)表示将整个数组的地址加一,(int*)(&a+1)表示将(&a+1)强制类型转换为int*类型。

所以本题的结果为:

题目二:

struct Test
{
	int mun;
	char *pcNmae;
	short sDate;
	char cha[2];
	short sBba[4];
}*p;
//假设p的值为0x100000
int main()
{
	p = (struct Test *)0x100000;
	printf("%p\n", p + 0x1);
	printf("%p\n", (unsigned long)p + 0x1);
	printf("%p\n", (unsigned int *)p + 0x1);
	printf("%p\n", (unsigned char*)p + 0x1);
	printf("%p\n", (unsigned char**)p + 0x1);
	system("pause");
	return 0;
}

题目分析:首先结构体为20个字节;

	printf("%p\n", p + 0x1);//0x00 10 00 14
	//p是(struct Test *)类型,是指针,该结构体大小为20个字节
	//p:0x00 10 00 00
	//0x1:在十进制中为1 
	//p+0x1=p+1=p+20个字节=0x00 10 00 14
	printf("%p\n", (unsigned long)p + 0x1);//0x00 10 00 01
	//p是(unsigned long)类型
	//p:0x00 10 00 00
	//0x1:0x00 00 00 01
	//p+0x1=0x00 10 00 01
	printf("%p\n", (unsigned int *)p + 0x1);//0x00 10 00 04
	//p是(unsigned int *)类型,是指针,32位平台下是4个字节,指向int类型的数据
	//p:0x00 10 00 00
	//0x1:在十进制中为1 
	//p+0x1=p+1=p+4个字节=0x00 10 00 04
	printf("%p\n", (unsigned char*)p + 0x1);//0x00 10 00 01
	//p是(unsigned char*)类型,是指针,32位平台下是4个字节,指向char类型的数据
	//p:0x00 10 00 00
	//0x1:在十进制中为1 
	//p+0x1=p+1=p+1个字节=0x00 10 00 01
	printf("%p\n", (unsigned char**)p + 0x1);//0x00 10 00 04
	//p是(unsigned char**)类型,是指针,32位平台下是4个字节,指向char*类型的数据
	//p:0x00 10 00 00
	//0x1:在十进制中为1 
	//p+0x1=p+1=p+4个字节=0x00 10 00 04

所以,题目的运行结果为:

题目三:

int main()
{
	int a[4] = { 1, 2, 3, 4 };
	int *ptr1 = (int *)(&a + 1);
	int *ptr2 = (int *)((int)a + 1);
	printf("%x %x\n", ptr1[-1], *ptr2);
	system("pause");
	return 0;

题目分析:首先我们先介绍一下什么是大小端存储,大端:是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中;小端:是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中。而数组是在栈中存储的。题目中(int)a是把地址强制类型转换成数值,则+1加1个字节;(int *)((int)a+1)则把上一步转换得到数值强制类型转换成(int *)类型。小段存储,大端打印。

数组的存储方式:

题目中的指针指向:

数据的小端存储:

所以,题目的结果为:

题目四:

int main()
{
	int a[3][2] = { (0, 1 ), ( 2, 3 ), (4, 5 ) };
	int *p;
	p = a[0];
	printf("%d\n", p[0]);
	system("pause");
	return 0;
}

题目分析:本题二维数组中蕴含着逗号表达式,在逗号表达式中,取每一个表达式中最后一个数据。

所以,指针P的指向以及数组a的存储我们可以想象成是这样的:

题目中的p[0]=*(p+0),所以本题的结果为:

题目五:

int main()
{
	int a[5][5];
	int(*p)[4];
	p = (int(*)[4])a;
	printf("%p,%d\n", &p[4][2] - &a[4][2],&p[4][2] - &a[4][2]);

	system("pause");
	return 0;
}

题目分析:在做本题之前首先需要搞清楚p[4][2]以及a[4][2]分别代表什么,题目中二维数组a为5行5列,而数组指针p指向一个为5行4列的二维数组,p[4][2]=*(*(p+4)+2),a[4][2]=*(*(a+4))。我们在开篇已经讲过,二维数组我们可以想象成由几个简单的一维数组组成,所以数组指针p指向的地址就是5行4列数组的第一行的地址,所以p+4加16个字节。如图所示:

由图可知:p[4][2]与a[4][2]之间差了4个字节

所以&p[4][2] - &a[4][2]以%d形式打印-4
而-4的二进制表示为:
原码:1000 0000 0000 0000 0000 0000 0000 0100
反码:1111 1111 1111 1111 1111 1111 1111 1011

在内存中是以补码存储:

补码:1111 1111 1111 1111 1111 1111 1111 1100

而地址是以16进制打印:
16进制:FF FF FF FC
所以&p[4][2] - &a[4][2]以%p形式打印FF FF FF FC

所以本题的结果为:

题目六:

int  main()
{
	int a[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9,10 };
	int *ptr1 = (int *)(&a + 1);
	int *ptr2 = (int *)(*(a + 1));
	printf("%d %d\n", *(ptr1 - 1), *(ptr2 - 1));
	system("pause");
	return 0;
}

题目分析:首先,需要明确&(a+1)表示整个数组+1,(int*)(*(a+1))表示将*(a+1)强制类型转换成为(int*)类型,其次在二维数组中数组名可以理解为第0行的地址,所以a+1表示第一行的地址。画图解题即可,如图所示:

所以,本题的结果为:

题目七:

int main()
{
	char *a[] = { "work", "at", "alibaba" };
	char **pa = a;
	pa++;
	printf("%s\n", *pa);
	system("pause");
	return 0;
}

题目分析:本题难度不大,只需找到指针pa初始指向的位置以及指针变量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);
	system("pause");
	return 0;
}

题目分析:在做题目之前,首先需要明确题目中出现的操作符的优先级以及结合性,题目中出现的操作符优先级以及结合性从高到低依次为下标引用[ ]、从左向右;前置++、从右向左;前置--、从右向左;解引用*、从右向左;加法+、从左向右。还要注意前置++与前置--运算后,cpp将会被改变,如果上一个语句中使用前置++或前置--运算后,下一条语句将使用改变后的cpp。

初始时指针数组c、cp以及指针cpp所指向的位置如图所示:

printf("%s\n", **++cpp):图示:

所以*(*++cpp)后得到POINT。

printf("%s\n", *--*++cpp+3):图示:

所以*--*++cpp运算后得到ENTER,+3得到ER。

printf("%s\n", *cpp[-2]+3):*cpp[-2]+3=*(*(p-2)+3)图示:

所以*cpp[-2]运算完后得到FIRST,+3得到ST。

printf("%s\n", cpp[-1][-1]+1):cpp[-1][-1]+1=*(*(cpp-1)-1)+1。图示:

所以cpp[-1][-1]运算完以后得到NEW,+1得到EW。

所以本题的运行结果为:

总结:这8道题考查了二维数组的访问、数组的存储、大端模式、小端模式、数组名与&数组名+1所代表的含义、操作符结束运算后变量是否发生改变以及指针的运算,画图更加便于理解数组与指针相结合的题目,希望大家可以加深理解。

  • 27
    点赞
  • 181
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值