算是自己的指针与数组本质的学习笔记吧.发出来给大家分享一下.如有错误,大牛们就指导一下吧.
看代码的时候看见一段没怎么看明白的代码..:
unsigned int *PageDirectoryEntry=(unsigned int *)0xC0300000;
.......
.......
PageDirectoryEntry[i]&0xFFFFF000
PageDirectoryEntry[i]这个能想明白,但是好像还不是真正的懂.(就是自己还不能明白其奇妙之处..) 于是又看了看数组与指针..
谭爷爷的书里:
int a[]={1,0,2,3};
int *p;
p=a;
for (int i=0;i<=3;i++)
{
printf("%d",p[i]);
}
那上面的就是强制的把*PageDirectoryEntry转成了一个起始地址为0xC0300000的指针数组了.
PageDirectoryEntry[i]就容易明白了.
资料上是这么说的:
1、指针的本质是一个与地址相关的复合类型,它的值是数据存放的位置(地址);
数组的本质则是一系列的变量。
2、数组名对应着(而不是指向)一块内存,其地址与容量在生命期内保持不变,
只有数组的内容可以改变。指针可以随时指向任意类型的内存块,它的特征是“可
变”,所以我们常用指针来操作动态内存。
3、当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针。
这样我自己有动手实践了一下:
[FONT=Arial][COLOR=black][COLOR=black][FONT=Arial]#include "stdafx.h"[/FONT][/COLOR]
[COLOR=black][FONT=Arial]int main(int argc, char* argv[])[/FONT][/COLOR]
[FONT=Arial][COLOR=black]{[/COLOR][/FONT]
[FONT=Arial][COLOR=black]char a[] = "Hi,ABC!";[/COLOR][/FONT]
[FONT=Arial][COLOR=black]char *p = "Hi,ABC!";[/COLOR][/FONT]
[FONT=Arial][COLOR=black]for (int i=0;i<=7;i++)[/COLOR][/FONT]
[FONT=Arial][COLOR=black]{[/COLOR][/FONT]
[FONT=Arial][COLOR=black]printf("%c%c\n",a[i],p[i]);[/COLOR][/FONT]
[FONT=Arial][COLOR=black]}[/COLOR][/FONT]
[FONT=Arial][COLOR=black]return 0;[/COLOR][/FONT]
[FONT=Arial][COLOR=black]}[/COLOR][/FONT]
[/COLOR][/FONT]
在VC中反汇编为(看过天书的人应该比较熟悉吧):
6: int main(int argc, char* argv[])
7: {
00401010 push ebp
00401011 mov ebp,esp
00401013 sub esp,50h
00401016 push ebx
00401017 push esi
00401018 push edi
00401019 lea edi,[ebp-50h]
0040101C mov ecx,14h
00401021 mov eax,0CCCCCCCCh
00401026 rep stos dword ptr [edi] //处理局部空间的初始化
8: char a[] = "Hi,ABC!"; //我们看看是怎么对数组a的处理的
00401028 mov eax,[string "Hi,ABC!" (00422024)] //把a的前4项:Hi,A 的ASCII码保存在了eax ,下面又把它放在了局部变量空间里面
0040102D mov dword ptr [ebp-8],eax
00401030 mov ecx,dword ptr [string "Hi,ABC!"+4 (00422028)] //后3项的处理(为了CPU取数据快些,变量都是存放在偶数内存空间的)
00401036 mov dword ptr [ebp-4],ecx
9: char *p = "Hi,ABC!"; //我们看看对于指针的处理,offset明白了吧,是把字符窜的地址存放在局部空间里
00401039 mov dword ptr [ebp-0Ch],offset string "Hi,ABC!" (00422024)
10: for (int i=0;i<=7;i++)
00401040 mov dword ptr [ebp-10h],0
00401047 jmp main+42h (00401052)
00401049 mov edx,dword ptr [ebp-10h]
0040104C add edx,1
0040104F mov dword ptr [ebp-10h],edx
00401052 cmp dword ptr [ebp-10h],7
00401056 jg main+6Ah (0040107a)
11: {
12: printf("%c%c\n",a[i],p[i]); //下面是重点了,数组与指针的不同
00401058 mov eax,dword ptr [ebp-0Ch] //指针p的值
0040105B add eax,dword ptr [ebp-10h] //p+1
0040105E movsx ecx,byte ptr [eax] [COLOR=red]//这个是理解的关键,需要再一次取地址转换,才能得到字符串的值!![/COLOR]
00401061 push ecx
00401062 mov edx,dword ptr [ebp-10h] //i的值
00401065 movsx eax,byte ptr [ebp+edx-8]//从a的位置开始,向后移动i个字节,然后取出其中的字符。
0040106A push eax
0040106B push offset string "%c%c\n" (0042201c)
00401070 call printf (004010b0)
00401075 add esp,0Ch
13: }
00401078 jmp main+39h (00401049)
14:
15: return 0;
0040107A xor eax,eax
16: }
那么指针和数组的本质区别:
内存布局分别:
数组a需要在内存中占用8个字节的空间,这段内存区通过名字a来标志。指针p则需要4个字节的空间来存放地址,这4个字节用名字p来标志。其中存放的地址几乎可以指向任何地方,也可以哪里都不指,即空指针。目前这个p指向某地连续的8个字节,即字符串“Hi,ABC!”。
另外,例如:对于a[1]和p[1],二者都返回字符‘i’,但是编译器产生的执行代码却不一样。对于a[1],执行代码是从a的位置开始,向后移动1两个字节,然后取出其中的字符。对于p[1],执行代码是从p的位置取出一个地址,在其上加1,然后取出对应内存中的字符。
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)