【C】指针的相关运算练习题

前言

嗨喽,大家好~这里是咸鱼安忆.

现在是学C语言时刻~

C语言当中的指针向来是一个难点

本篇文章针对指针的相关运算列出了一些例题供以研究学习

希望看完本篇文章之后,你能有所收获~

例题一

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) 取出的是第二个元素的地址,解引用之后就是2

(ptr-1) 中ptr里存放的地址是由&a+1得到的,&a取得的是整个数组的第一,+1跳过整个数组,ptr就指向了5后面的地址,而ptr-1得到的就是5的地址了,解引用得到结果5

例题二


struct Test
{
	int Num;
	char* pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}* p;
//假设p 的值为0x100000
//此结构体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 + 0x1这个结构体p一共20个字节,加0x1等于加了一位,就加了20,记住要转为16进制,所以第一个是0x100014

(unsigned long)p + 0x1将p转为了无符号长整型,所以加的就是1,结果为0x100001

(unsigned int *)p + 0x1将p转为了无符号整型指针,跳过的就是一共整型指针的大小,加了4,结果为0x100004

例题三

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);
	return 0;
}

!Visual Studio 2019所采用的是小端存储

ptr1所得到的是&a+1的地址,&a取到的是整个数组的地址,当它+1之后,就跳过了一整个数组,拿到了4后面的地址

而ptr1[-1]与 * (ptr1+(-1)) 等价,所以ptr1-1得到的就是4的地址,而结果用%x,也就是十六进制输出,结果为0x00000004,0x和0都会被省略,结果输出4

ptr2所得到的是首元素地址a被强转为int型之后+1得到的

因为a原本是int*占4个字节,转为整型之后就意味着地址变成一个整数了,所以+1加的的就是十进制1,整型+1跳过一个字节

地址变成首元素后的第二个字节的地址,在小端存储下取出得到00 00 00 02,十六进制是0x02000000,输出结果为2000000
例题三图解

例题四

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

数组初始化内(1, 0)是一个逗号表达式,结果是1,所以 p [0] = 1

例题五

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

p=a将a的地址赋给了整型指针p

而p[4]取到的相当于从a的首地址开始,每四个字节一组,来到了a[3][1] 的位置

p[4][2] 就是取到这一组元素的下标为2的地址,求得a[4][2]的地址,再将他们相减得到-4

而-4用%p打印成十六进制则是FFFFFFFC,%d的结果为-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;
}

赋值过程如图解,其中*(ptr1-1)就是解引用ptr1前一位的地址,也就是10
而*(ptr2-1)就是解引用ptr2前一位的地址,(int*)这个强制转换是用来迷惑的,因为本来就是int型
例题六图解

例题七

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

如果能理解前面的内容,此题就比较简单,二级指针pa取到了a的首元素地址,pa++就是a的首元素地址往后走一位,这里重点就在于了解数据是如何存储的,具体如图:

例题七图解

例题八

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

此题较为复杂,首先需要了解一下他们的存储结构和指向关系,存储结构图解:
例题八图解
了解了他们之间的关系之后我们再来开始计算:

1、

(**++cpp)

++在cpp之前,先加再运算,cpp本来是指向cp的首元素地址的,++后指向了(c+2)的地址,一次解引用得到c+2,第二次解引用得到POINT

2、

(*-- *++cpp+3)

+的优先级是比较低的,所以这里我们先运算++和解引用符号

cpp因为上一条语句的运算,现在指向的是(c+2)的地址,++后指向了(c+1)的地址,解引用后得到了c+1,–后使得(c+1)变成了c

此时再解引用得到了c的第一个元素”ENTER“的首元素地址,最后在+3得到第二个E的地址,用%s打印出来就是ER

3、

(*cpp[-2]+3)

可以先将cpp[-2]转换为 *(cpp+(-2)),得到的表达式就是

(* ( *(cpp-2))+3)

然后再将这个表达式一步步运算,先是cpp-2,现在的cpp还是指向(c+1)的地址,地址-2后得到了(c+3)的地址,

不过要注意,这里只是在运算表达式而没有将cpp真实指向的地址改变

得到(c+3)的地址后再解引用得到(c+3),再进行解引用得到c的第四个元素”FIRST“的首元素地址,最后再+3打印出来得到ST

4、

cpp[-1][-1]+1

首先还是将表达式转换一下,得到:

  • ( *(cpp-1)-1)+1

然后再进行运算:
cpp-1得到(c+2)的地址,解引用得到(c+2),再-1得到c+1,解引用得到c的第二个元素"NEW"的首元素地址,最后+1得到E的地址,用%s打印出来得到EW

尾语

感谢你看到这里~

希望本篇文章有对你带来帮助 😁,有学习到一点知识~

躲起来的星星🌟也在努力发光,你也要努力加油(让我们一起努力叭)

此篇文章通过对相关例题的练习和了解,能够更加深入地了解了数据的存储结构,指针的相关运算,理清地址与元素的关系

如果解析有什么不对的地方,欢迎在评论区评论点评和交流。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值