c语言中,是如何根据指针取出数据的?
1.定义一个结构体:
struct test{
int a;
double b;
} me;
test* pointer=&me;
这时通过pointer->a,pointer->b是如何根据一个指针地址,取出结构体数据的?
2.定义一个数组:
int a[100][100];
访问a[99][100]
肯定会越界,系统是怎么判断出来的,是根据访问的地址超出了向操作系统申请的范围判定的??
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
1、变量对应内存一块单元,知道变量的起始地址,知道变量的类型,就可以取出变量内容。point是个指针,保存了me的地址,me的内存模型是int+double,point->a可以取到a的地址,也就可以拿到内容。
2、我用VS2012做了下实验,会有三种结果。大部分时间能正常运行,还有可能是读取99内存出错或者是栈溢出。看看汇编可以发现编译器并没有做溢出判断。可以猜测,运行会不会出错取决于你越界访问的内存的属性。
我只回答第二个问题,C语言最终要经过编译,转成可执行程序,可执行程序通过操作系统给硬件发送指令,操作系统为了防止硬件被错误读取,会增加一些防御性设计,比如对于栈内存的读取就会有限制,如果越界访问,就会报错。
1.编译的时候,编译器会就算每个元素的偏移字节数(这是一个常量),然后把pointer->b的指令编译为取pointer+b的偏移值地址的数据的指令。对于x86,有一个间接寻址方式可以直接用,先将pointer的值存入EBX,然后汇编指令指令MOV EAX, [EBX+0x02],这样取值。
2.和很多高级语言不同,C语言不会做数组越界检查,只要你越界的数据是系统允许访问的内存内容,都是会成功的。操作系统的虚拟内存机制会有一些保护功能,当你试图访问没有读写权限的内存时,会触发CPU异常中断,操作系统会处理并结束进程。不过这个机制并不能可靠得防止数组越界,只能防止你破坏常量、内核内存数据之类的。
我学的硬件,大致能给你说一些,系统和程序跑起来都在内存里,内存是有物理地址的,所以指针的应用更接近于底层,就是能方便的操作内存数据。就像老师讲的那样,内存的每个物理地址都对应一块空间,所以当你程序里使用指针的时候就是操作地址,如果知道物理地址的话,就可以读出里面的数据。
根据数据类型,数据类型决定了数据占用的内存空间,所以
pointer->a
可以理解为到pointer
所指向的内存中,读前4个字节的数据,这4个字节的数据也就构成a
的值。操作系统对不同内存有不同的
保护属性
,比如人家不想被你修改的就只允许读,一但侦测到写入操作就会报告段错误
或者`内存访问违规`。数组一般是可读写的,你访问数组出界,如果正巧访问的是另一块可以读写的内存,一般情况操作系统是不会报错的。如果访问到了其他受保护的内存,就抛出异常了。数组不过是申请了一块可以读写的内存让你操作而已。
想个问题,一个结构体占多少个字节是怎么算的? 是不是把他里面的数据类型所占的字节加起来就是这个结构体的总字节?而每个指针拿到的地址永远是他指向的那个数据类型所占的字节中的第一个字节的地址。因为定义了数据类型,所以他知道占几个字节,因此指针只要知道第一个字节的地址,下面的字节地址就能自动推出来(+1)。因为数据类型的字节地址都是相邻紧挨的。