【C语言】指针练习题目

提示:如果变强是我们共同的目标,那么锤炼就是我们共有的方式~
本文由@睡觉待开机原创,未经允许不得转载。
本内容在csdn网站首发
欢迎各位点赞—评论—收藏
如果存在不足之处请评论留言,共同进步!


前言(C语言与指针,指针与题?)

提示:这里可以添加本文要记录的大概内容:
指针,是C语言的灵魂所在,而题目,是掌握指针的关键,下面通过精选几道题目,带同学深入理解指针精妙之处~


提示:以下是本篇文章正文内容,下面案例可供参考

T1:

#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;
}
//程序的结果是什么?

题解:(下面通过图文解析来刨析本题目)
答案:2,5
为了便于大家理解,特地给大家作了图为大家参考:
在这里插入图片描述
1.首先,代码创建了一个每个元素为int类型的,名字叫做a,的一维数组,共计5个元素
2.之后代码(取地址数组名+1)这个取地址数组名怎么理解?这是整个数组的地址,这个取地址数组名的类型是int ✳[5],加一会跳过整个数组,地址来到数字5后面的内存空间,之后再将这个地址强制类型转换为int*类型
3.最后打印:第一个✳(a+1)是数组名加1,数组名是数组首元素的地址,其类型是int类型,加一会跳过一个int类型的长度空间,来到指向数字2的地址,解引用这个指向数字2的地址,会得到数字2,同理,ptr因为被强制转换为int类型,所以str-1会跳过一个int类型大小的空间,指向数字5的空间,解引用拿到数字5

T2:

//在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;
}

答案:0x100014,0x10001,0x10004;
同样,为了便于大家理解,我们以图的形式对main函数之前的代码加以解析,再以文字的形式简单介绍一下后面的代码含义:
在这里插入图片描述
之后,我们再来分析main函数中的打印函数:
1.p+0x10x1是一个十六进制数字,其值还是数字1,p是一个指针变量,是一个地址,一个指针加整数,跳过多大内存取决于变量p的类型的内存大小,我们从题目中可以看到,该结构体大小为20,所以跳过20个字节,得到地址:0x100014;
2.剩下两个的话,还是同样的道理,,但是需要注意:指针p加一个数字1跳过的字节取决于p类型的大小,但是一个数字加上一个数字是几就是几… p被强转为无符号longlong类型,,属于整形类型,不是指针!!!所以跳过1个字节到答案0x10001;
3.第三个跟第一个同理,指针加整数跳过几个字节取决于p指针的类型,int是4个字节,加一就是加一个int类型大小,跳过4个字节,得到答案0x10004。

T3:

代码如下(示例):

#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
解析:
这个题目,不知道有没有同学进坑呢?以为二维数组的存储方式是这样的:
在这里插入图片描述
但是,因为里面是逗号表达式,小括号里面的数字取最后一个,所以是这样滴:
在这里插入图片描述
1.int*p;这是创建了一个指向int类型的指针变量p;
2.之后有同学就奇怪了,怎么好像把第一行给p了???我们把二维数组首元素a【0】也就等同于一维数组a【0】第一行的名称,数组名称又等同于一维数组a【0】首元素的地址,也就是把数字1的地址给了p!!!
3.我们打印的时候,p【0】可以理解为✳(p+0),所以说顺利解引用拿到了数字1并进行打印~

T4:

//假设环境是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;
}

答案:FFFFFFFC,-4
解析:
本题的主要奇怪的地方呢是,数组a是由5个一维数组int【5】组成的,但是创建变量接收的时候,变量的类型是int*【4】的类型,我们下面通过画图来进一步理解:


在这里插入图片描述
我们知道:
&p[4][2]可以等价于&✳(✳(p+4)+2)
&a[4][2]可以理解为&✳(✳(a+4)+2)
那么放在咱们数组中,可以得出以下图表:
在这里插入图片描述
1.指针减指针,得到的是两者间的元素个数,所以说呢,第二个空答案是-4(因为是小地址-大地址)
2.至于第一个空,因为要打印地址,是按照16进制形式进行打印,并且编译器先把-4转变成为补码,-4变成11111111111111111111111111111100,而对于地址没有反码补码的概念,编译器将这个-4的补码直接转换为地址,变成FFFFFFFC,并打印出来~

T5:

#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;
}

答案:10,5
解析:
我们通过画图的形式,来进一步展示本题目中的逻辑关系,请仔细看图:
在这里插入图片描述
为什么ptr1-1往前走一个元素大小呢?因为被强转为了int*类型; str2也是一样的道理。

T6:

#include <stdio.h>
int main()
{
	char* a[] = { "work","at","alibaba" };
	char** pa = a;
	pa++;
	printf("%s\n", *pa);
	return 0;
}

答案:at
解析:
首先,
在这里插入图片描述
在这里插入图片描述
我们解引用pa,拿到的是a+1的内容,a+1的内容是一个地址,我们打印字符串的时候就是需要字符串首字母的地址,遇到\0停止打印,这样顺利打印at;

T7:

代码如下:

#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;

}

答案:POINT ER ST EW
解析:前面已经做过了六道指针题目,相比大家对于指针以及指针类型理解已经有了一定的认知,不妨最后一题我稍作解释,留下一部分空间供大家发挥:
在这里插入图片描述

总结(指针的理解)

本文以题目为切入点,举了7道典型题目,分别考究了对于指针的不同角度理解。
希望同学们对指针的理解能够有更深入的理解,加深理解~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值