加入黑客反病毒 登录
黑客反病毒论坛 返回首页

学者无界的个人空间 http://blog.hackav.com/?12617 [收藏] [复制] [分享] [RSS]

日志

C语言中的指针(二)

热度 2已有 328 次阅读2014-8-27 10:42 |个人分类:C语言|系统分类:技术原创

小事件:
上学的时候,有时我们一帮同学会要自己做个饭,能够多吃点肉的同时,还能互相调侃一下厨艺,非常欢乐。开始做的比较简单,我们会买一堆的菜,放在一个筐里或者箱子里,想要用的时候,就去那里拿,后来发现,有些不方便,于是有了区分,葱姜蒜放到一起,肉单独放在一个碗里,菜放在一起。我们不是在讲程序吗?最起码和计算机有点关系呀!其实我想引出的是一个规律:事情越做会像越有条理的方向发展。所谓的有条理,就是会按照人的逻辑组织事务,使得其看起来更符合人的使用习惯或者更符合人的审美。比如城市的建设规划,会因为各种原因,设计成一个圈一个圈的。。。再比如一个程序,在内存中会被分为不同的区域。
正文:
我们经常见到的EXE程序,他其实是程序一点一点进化的结果。可以想象,最开始,程序中的可执行代码和需要处理的数据,应该是在同一个区域中,甚至不同程序的代码和数据,也在一个区域中,比如这样:

代码和数据混在一起,可能上一句执行使用到的数据,就在临近的内存中。如果程序完全是这个样子的,那也完全可以。但是实在不符合人的审美和使用习惯。为了便于区分与查看,人们总喜欢归类,所以,将程序在内存中的排放分为了很多区域。代码区,数据区,单单一个数据区也不符合使用习惯,于是又把数据区分为了几个区域。另外,还用了一些复杂的方式,将不同的程序隔离了开来。
如此,程序一共运行所需要的区域有这些:
1 代码区
2 全局数据区(存储着全局变量,局部静态变量)
3 全局常量区(存储着字符串常量)
4 栈区          (存储着局部变量,函数的参数)
5 堆区          (存储啥得看情况)
一个程序的地址空间,是否完全被这几个区域瓜分??
答:不是
            1 还有一些程序的附加信息,和程序加载有关。这些区域和编程没有关系,一般也不会去访问他们。
            2 还有一些区域什么也没有存储,访问它程序会崩溃。我经常把程序的运行空间想象成一片无边无际的大海,而存储着数据和代码的内存,我把它看成海上的陆地,而有些什么都没有存储的地方,就像深不见底的海水,假如不小心你的程序访问了这里,就像掉到了大海,一般都会死无葬身之地。
于是现在的程序内存空间大概是这样子的(排列顺序可不是这样,这里只是表示他们都分类了): 

数据区域有这么多,到底有什么用?
我想这还是在慢慢的在编程过程中被人为设计出来的:
栈区:程序中有很多的变量,对于局部变量来说,一般只有定义它的函数中会用到它,离开了函数就不会再访问它,那么一个c程序函数千千万,局部变量总数万万千,如果都将其存储在一个区域中,内存利用率会很低。不如进入一个函数,分配一块内存,存储这个函数的局部变量。这么设计于是就有了栈区这么一个概念。随着进入,退出函数栈区空间在不断的增长,减少,极大提高了内存使用效率。
刚才还提到了一点:栈区还存储着函数的参数,当调用一个函数的时候,所以函数的参数你可以看成这个函数的局部变量。
堆区:有的时候,我们不知道到底要使用多少内存空间,存储一些数据,比如,我们要搜集一下北京各个区有多少辆车,只有在搜集完了之后,才有可能知道有多少辆车,在这之前是不会知道要用多少个元素的数组去存储他们的。我们只能在程序运行中动态的分配需要的内存,动态分配内存在c中用malloc ,在C++中用new。
全局数据区:也叫静态数据区,全局变量是在很多函数中都可以使用的变量,放在不断消涨栈区中,肯定是不合适的,将它们放在了一个空间大小不会变化的区域,静态变量,也是不随着函数的进入退出而变化的,它也被放到了全局数据区。
故而:全局变量和静态变量,他们的区别,其实也就是作用范围的不同。
常量区:有一些数据,是不想被修改的。比如一个字符串常量,或者一个全局const常量,他们都是在这个区域中。
代码区:存储着程序的代码。
为什么要提这些个区域?
因为,指针变量可以存储这些区域的地址,从而产生不同的用法。
堆区和栈区:
栈区空间是系统根据进入函数退出函数,自动的增长或消除。堆区是根据需要程序员自己调用malloc或者new申请的,系统也不知道你什么时候用完,所以系统不会自动的释放,需要程序员调用free或者delete去释放这些空间。(注:一段空间只能被释放一次。)
关于目前所讲到的常见错误:
定义了一个指针直接释放:
int *p;
free(p);
错了,p没有指向一个有效的堆空间。
用指针指向了一个栈区空间,然后释放他:
int a[10];
int* p =a;
free(p);   //错啦
一片空间释放了两次:
int *p1 = (int *)malloc(8);
int *p2 = p1;
free(p1);
free(p2);
错了,两个指针存储着同一个堆空间地址,这样的话就释放了两次。
使用某一个函数需要传入一个缓冲区:
比如一个函数是这么定义的:
strcpy(char* p1,char *p2);
这个函数只想让你传进去两个指针吗?不是,它是想让你传入一个有效区域的地址,然后往这个区域写东西。或者从这个区域读东西。
这有效的区域就是堆区,或者栈区。
比如你可以这样:
char *p = (char*)malloc(10);
strcpy(p,"hehe");
或者
char p[10];
strcpy(p,"hehe");
常量区:
你要使用一个字符串,程序中必然得有这个字符串才行。对于一个字符串常量,它其实是存储在常量区中的。最常见的错误,就是尝试改变常量区的值。
比如:
char *p = “15pb”;
p[0] = 'h';
第二句会报错,p指向了常量区,尝试修改常量区,就会报错。
代码区:
指向代码区的正常用法,就是用函数指针指向那里,然后去调用那里的代码。
函数指针和函数一样:
需要明确返回值类型,参数个数和类型。才能调用
返回值 (*指针变量名)(参数1,参数2......)
非正常的用法:
比如:
将基本类型的指针指向代码区,然后取出其中的代码,做做反汇编。
到目前应该了解了指针的各种类型,各种类型有什么特性,以及指针能够指向的区域,指向不同的区域分别又有哪些特性。


路过

鸡蛋
2

鲜花

握手

雷人

刚表态过的朋友 (2 人)

全部作者的其他最新日志

评论 (0 个评论)

facelist

您需要登录后才可以评论 登录 | 加入黑客反病毒

关闭

站长推荐上一条 /2 下一条

Archiver|手机版|小黑屋|黑客反病毒组织 ( 京ICP备12031837号-2 )  

GMT+8, 2018-5-20 17:52 , Processed in 0.154440 second(s), 24 queries , Gzip On.

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

返回顶部