学逆向最重要的基础就是c/c++,而学c其实就是学指针,指针的重要性不言而喻,而阻挡大家的指针,其实并没有那么难理解,我们一起看看吧!
学习指针前必须了解内存是个什么样子的,不然无法理解指针的概念
| a | 0x0
| b | 0x4
| c | 0x8
| d | 0xC
| e | 0xF
这就是一个基本的内存模型,每一行代表一个内存,格内代表内存,格内内容代表存入的值,格后方标号代表内存地址
我们每次在申请变量时,如 int x=0x15; 其实是在内存中申请了一段空间,int代表申请四字节,x是变量名,0x15是值。
对应上图中第一行,在格内放入变量名为x、值0x15的一个四字节变量。
这里知识点出现了:在32位系统下,一个内存地址就是四个字节,所以我们申请一个int,相当于占了一整行,也就是一个内存空间,而内存空间的地址为编号0x0。
它在内存里长这样:
| 00 00 00 15 | 0x0 (其实此处涉及大小端序的问题,但是为了方便理解我们先以大端序为例)
理解了这个,我们再来想一下,如果我申请的是 char x=0x15; 会怎么样呢?
没错,因为char只占一个字节,第一行没被占满,其实内存是这样的:
| 15 00 00 00 | 0x0
本例后面这三个地址是没有被分配的,而上例中4个字节均被分配了。
好的,到这大家其实已经把指针学明白了。嗯?你不都没提指针吗?
对,指针就是存放标号的变量而已,值就是格子右边的0x0。至于指针有类型只不过是它每移动一次是几个字节而已,这个放到下面讲。
此处你只需要记住,指针是一个变量,它的值是地址的值就好了。
在c语言中数组其实与指针有着千丝万缕的联系。
首先我们来看一段代码:
首先这里有一个变量a和一个数组b,其中pa是a的指针(&符号是取地址的意思),pb是b的指针。
到这里细心的小伙伴应该发现了,你不是说pb是b的指针吗,为什么不加取地址符号?这里就是我们学习指针要过的第一个坎:数组名其实就是指针!
我们先不看b和pb,大家都知道pa其实是a的地址,而通过指针访问a的写法为*pa,那pa+1呢?没错,是a的地址加上4个字节,同理访问其值的写法为*(pa+1)。
那有了这个基础,我们先来看一下b的访问,如果你想取数组的第一个值,你得写b[0],
第二个b[1]。如果用pb访问呢?分别为*pb,*(pb+1)。嗯?到这里是不是发现了什么?没错!就是你想的那样。数组的访问其实是指针加偏移的形式访问的,所以说数组名其实就是指针!
我们打出b和pb:
到这里就完了吗?怎么可能,到这完了肯定有大佬喷我了。那我们忽略了哪里呢?就是&b和&b+1到底指向哪里,我们打出来看看:
聪明的小伙伴已经明白了吧,&b时指向的还是数组b的第一个数据的首地址,而整个数组b指针的加1,要加上整个数组大小进行地址偏移(本例中是5个地址偏移)。
最后我们再从汇编层面看看数组访问时的行为:
没错吧!其实底层的行为就是基址加偏移访问的。
到这里,指针基本就学完了,我们来解决下遗留问题:
一、指针的类型
从上面例子中不难看出,我们一直使用的是int*类型的指针,而它每次加1就会移动四个字节。如果我们换成char*类型的呢?
没错那每次就移动一个字节,当然这样的话就会遇到一些问题,但是这些问题是可以预测的,
当然会涉及到大小端序,在此处就不讨论了,大家感兴趣自己去试试就好了
二、指针数组和数组指针
这个其实很多人分不清,但是没必要。这只是个文字游戏而已,我区分他们的方法很简单,就是中间加个的。
"的"字后面出现的是关键:指针的数组,表名它是数组,而每个数组的内容是由指针构成的。
数组的指针,表名它是指针,是指向数组的指针,上面已经提到了,就是那个加1时会移动整个数组长度的指针。
三、函数的指针
函数指针也没啥新鲜的,依旧是指针。只是定义时比较特别需要typedef。它的关键在于可以直接通过指针加参数的形式调用。
它可以传参调用函数,这是重点也是难点,这样一来它的应用就比较灵活了,因为你可以通过一个指针调用不同函数。
这也是高级编程中经常使用的方式,如果有兴趣可以自行研究。
本期的内容就到这里了,大家有什么建议和问题一定要骚扰我哈,也欢迎大家加微信讨论,联系方式在我的博客--杂七杂八--置顶的那篇文中。
原文:https://www.cnblogs.com/TJWater/p/14403951.html