指针的进一步学习

154 阅读3分钟

0.暴力枚举

给10元,5元,2元,1元的纸币各若干张,若纸币总数不超过40张且总金额为100元,计算多少种分配方法。最简单有效的办法:暴力枚举,也就是把所有情况都列出来,看每一种情况是否满足要求。每种纸币的张数最多不超过40张,因此我们可以在0到40张之间对每种纸币暴力循环,符合要求就计数: 截屏2022-02-06 下午7.18.21.png

可想而知,这样暴力的次数,不论从时间和空间上都是极大开销,是否可以改良?答案是肯定的。 由于每种类的纸币至少也要一张,因此: 对于10元的纸币,最多只能有9张即90元,10张时已经金额达标但其他种类不能出现,因此10元的张数极限为9; 对于5元的纸币,最多只能有19张,20张金额达标其他种类不能出现,因此5元张数极限为19...以此类推,可得如下改良方式: 截屏2022-02-06 下午7.22.35.png

1.指针的值址传递

指针的本质是地址,那么指针的实际应用在何处呢?归纳下来,指针很多情况下都是应用于数据的传递。

1.1 值传递

我们经常需要对一些数据进行处理,这需要我们把他们作为参数传入对应的处理函数,在函数内进行处理,而对于这种参数的传递,c语言中共有两种:值传递和址传递。先写一段代码:

截屏2022-02-06 下午8.17.56.png

我们定义了一个变量i,赋值为10,紧接着将其传入change函数,但是很显然传入后将i打印,依然值不变为10,这是为什么?是因为我们在传递参数的时候,只是把i作为实际参数传过去传至change函数的形参,相当于只是把i的值赋值给形参。c语言中不同的函数模块在内存中是有着不同的所属内存空间的,我们来看一张内存示意图:

截屏2022-02-06 下午8.17.20.png 在图中,由于程序的入口是main函数,因此编译器为main函数分配了一段内存空间,这段内存空间中像代码描述的那样,定义了一个i赋值为10,而后进行传参调用change函数时,编译器再为change函数及其形参开辟了一段空间,将实参i的值赋值给形参j,虽然在change函数内部对j进行了改变,但是很显然这是两段空间,对j的改变与i无任何关系,所以i仍然是原来的值10。

1.2 址传递

说完了值传递,再来说说址传递。顾名思义,传递的参数不再仅仅是值,而是地址。虽然也是赋值,但赋值的是地址,而我们可以根据地址找到这个地址对应的变量,从而对变量的值进行改变,如下图: 截屏2022-02-06 下午8.25.59.png 我们把地址作为参数进行传递,在change函数中改变的就是参数地址对应的变量,也就是本身的i,因此i的值变为了5。

2.指针的偏移

前面说过,数组的名字就存储着该数组的首地址。因此对地址的操作,也就可以对相应的地址指向的变量进行操作,对地址的乘除是无意义的,因为数组的元素存放是相邻地址空间,因此我们可以对地址进行加减,以取得其前后的地址,从而操作其变量值: 截屏2022-02-06 下午8.43.56.png