c语言malloc如何释放动态申请的(malloc)指针数组?

给指针malloc分配空间后就等于数组吗? | 日志 | 果壳网 科技有意思
这是对帖子内容的回答。 由于一时兴奋写的过长,期间果壳抽来抽去,最后还导致排版彻底失败。。于是还是决定写成一篇日志。首先回答这个的问题:严格的说不等于数组,但是可以认为它是个数组一样的使用而不产生任何问题。不过既然这样,那它应该算是个数组吧。所以,一般我们都用“动态数组”这种名字来称呼这种东西。要讲清楚这个东西,涉及到malloc函数,指针类型和“[ ]”下标运算。======分割线[0]======malloc是C的标准库函数之一,用来分配动态内存。一般来说,由C/C++编译的程序会在运行的时候在内存中占用一些空间,它们分为以下几个部分:1.二进制代码区 不必过多解释了,就是放二进制代码的地方。2.常量区 存放文字字符串和常量3.静态存储区 存放静态和全局变量4.堆空间 动态内存区,程序员可控制分配和释放的区域。5.栈空间 由编译器分配内存用于存储函数参数和普通变量。malloc能操作的是程序中的堆空间,而普通的数组则是存放在栈空间里面的。由于操作系统对这两部分的内存管理模式差别很大,所以我们一般认为是不同的。堆空间是系统内存中的可用区域,和普遍意义上的“堆(Heap)”不同,基本上可以看作是由空闲内存组成的大链表。嘛,操作系统怎么处理这东西不管了,反正你就可以认为堆空间是可用内存里的一片连续区域。malloc函数的作用就是从这一片内存中划出一块空间来。你可以认为是malloc从内存中找到了一片可以安全存放数据的可用空间,这样你的数据就可以放在这片空间里面。这片空间的大小是你自己指定的。通过malloc(字节数)这样简单的方法。为了找到这片空间,malloc函数会告诉你这片空间开头的地址,你可以把它赋值给一个变量存放起来。这样我们就知道申请到的这片内存的首地址(malloc返回)和大小(程序员指定)了。======分割线[1]======这部分先放着,我们来看指针类型。C语言的指针也有类型,但是指针总是内存地址,是一个(32位/64位)二进制整数,长度也好大小也好都是确定的,理应一种类型就够了。那么,指针类型的作用是什么呢?其实指针类型就是用于判断指针所指向的数据的类型。不得不说这是一个非常天才的设计。指针里存放着的是一个地址,它能找到一个内存单元(复杂的东西不说了,操作系统都给你做了,你就认为是某一个字节就好。这个括号内部的东西写给某些较真的人看,实际上并不存在一种叫做内存单元的东西。),但是数据有长有短,数据们有些存在1个内存单元里面,有些存在多个内存单元里面。指针是为了指向一个数据,那么,用什么方法可以知道这个指针想要的,到底是几个内存单元里的数据呢?C语言里用了一种十分巧妙的设计——指针类型。一个指针指向一个字节地址,这个指针的类型所代表的数据结构是8个字节,那么我们就把这8个字节里面的东西都读出来,作为这个指针所指向的数据的值。举个栗子:比如说从地址是1000开始的内存是以下的一片样子:11 10 0100011 10 10000然后我有个指针a,它的值是1000。如果这个指针是int *a。当我用*a去访问数据的时候,就会返回【11 】这些数据。但是如果这个指针是double *a。当我用*a去访问数据,返回的就是【11 10 01000】这些数据了。不过这个指针值可是没有变化的,变化的只是指针类型而已。======分割线[2]======再回到原来那个问题,我们现在用malloc取得了一片空间,但是要让编译器知道其中每个数据占多少空间,就是由指针类型来确定了。这就是为什么malloc函数在赋值给指针之前要有一个强制类型转换的原因。否则void *类型一般应该是读不出数据的。(此括号再次写给较真的人们,直接使用void *指针是未定义行为,未定义行为是编译器说了算的,它不想给你返回值就不给你返回值了。不过我们现在的编译器都比较好心,一般是会给你返回1个字节的值的,用起来大概就和char *一个感觉。)比如说a=(int *)malloc(10240);这一段代码就取得了10240个字节(10KB)的可用空间,然后把首地址告诉了变量a。然后我打算存放的数据是整型的,一次要求程序在这段内存里面读4个字节返回。所以我使用了(int *)来确定指针类型。这样,当我们使用*a时,就可以访问到从a指向的地址开始的4个字节里面的数据了。======分割线[3]======可是我们申请了10240个字节呢。。。能存2560个整型变量呢。只能访问前4个字节有什么用?难道要每4个字节申请一次?怎么访问后面的内存空间呢?我们可以移动指针,比如把指针往后移4个字节。这样就能访问到这片区域里面的第2个整型变量了。(注意,如果是int *类型的指针a,把a往后移4个字节的操作是a=a+1,千万不要搞成a=a+4了。为什么这么做原因后面再讲。)/*补充[0]*/可是还是很麻烦,如果我要一次一次的遍历这片区域,或者同时访问里面的第12个和第450个变量。那么程序里就必然存在2个或2个以上的指针。为了简化访问方法,C语言使用了一种简单的对指针运算——[ ]下标运算。[ ]运算符是C语言几乎最高优先级的运算符。[ ]运算符需要两个操作数,一个指针类型,一个整数。/*补充[1]*/标准的写法是这样的:a[int]。这样编译器会返回 *(a+int) 的值。这样做的话相当于一个十分好用的临时指针的移动。如果我要访问第12个变量只需要写a[11]就好了。编译器会理解这个运算的规则,自动的把a指针进行一次以下的操作:int *temp=a+11;return *嗯,大概就是这个样子。======分割线[4]======该回到正题了。因为C语言为我们提供了这样的方法,使得我们申请到的一片内存连续区域,可以使用这样的方法,像数组一样的访问到。不过数组明显更加简单。int a[2560]同样是申请一片10KB的空间,这部分空间存放在栈空间里面。内存地址也是完全连续的。值得注意的是,数组名a其实被声明为常量指针const int *,它同样存储的是数组的首地址。(本括号写给较真的人看,C/C++自动把数组类型隐式声明为常量指针,这个动作其实更类似于隐式转换,而不是直接声明那个指针。)然后这么说来[ ]。操作符在普通数组上和用malloc生成的动态数组上的操作是完全一样的,都是类似于*(a+i)的操作。所以从这层意义上来讲,用malloc分配的空间本质上和数组没什么区别。它们主要的区别还是存放的内存区域在操作系统对内存管理上的区别。不过这层区别也不小,所以一般不把malloc分配的空间等同为数组,而是用“动态数组”来区别的对待它。最重要的区别也许就是使用完了以后记着用free释放掉。======分割线[5]=完,下面是补充内容=====补充[0]:操作系统给你分配的内存,一般只有栈空间是连续的。比如你申请一个10KB的堆空间区域,其实很少能申请到全连续的一段内存。一般都是中间会有断开的方式。操作系统是用类似于链表的方式来管理这些分片的内存空间的。所以说,虽然指针本质就是个整数,但是指针的运算不是简单的改变这个整数,而是指向下一存储区这样的意思。因为如果是让你简单的改变这个整数,很可能这个指针指向的就是内存中其他程序的区域了。甚至是系统重要的代码区域。这是绝对不允许的,所以编译器才会采用这样的定义。即给int *a定义的指针a进行a++这种运算的过程实际上相当于:1.返回a的当前值 2.找到a当前的内存区域 3.在链表中查找下4个字节的存放区域,并把首地址赋值给a。补充[1]:事实上ANSI C并没有定义两个操作数的顺序。指针[整数]只是一种常用写法。写成整数[指针]也未尝不可。定义数组int a[20]之后,使用5[a]一样可以访问到这个数组里第6个整型变量的值。======分割线[6]=参考资料=====
本文由授权()发表,文章著作权为原作者所有。
想写然后却悲催的发现居然会自动被果壳转换成斜体。。。。。
引用 的话:想写然后却悲催的发现居然会自动被果壳转换成斜体。。。。。这就是我排版失败的原因。。。
好长好长啊感觉……
不管怎么说真是谢谢大大了,现在才看到……
(C)2014果壳网&京ICP备号-2&京公网安备C语言_ch08_6_指针数组与多重指针 动态内存分配_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
文档贡献者
评价文档:
喜欢此文档的还喜欢
C语言_ch08_6_指针数组与多重指针 动态内存分配
c​语​言​。​山​东​大​学​,​通​信​,​谭​浩​强
把文档贴到Blog、BBS或个人站等:
普通尺寸(450*500pix)
较大尺寸(630*500pix)
大小:713.00KB
登录百度文库,专享文档复制特权,财富值每天免费拿!
你可能喜欢C语言中动态初始化字符指针数组malloc函数怎么用的?
C语言中动态初始化字符指针数组malloc函数怎么用的?
08-10-15 & 发布
一、malloc()和free()的基本概念以及基本用法: 1、函数原型及说明: void *malloc(long NumBytes):该函数分配了NumBytes个字节,并返回了指向这块内存的指针。如果分配失败,则返回一个空指针(NULL)。 关于分配失败的原因,应该有多种,比如说空间不足就是一种。 void free(void *FirstByte): 该函数是将之前用malloc分配的空间还给程序或者是操作系统,也就是释放了这块内存,让它重新得到自由。 2、函数的用法: 其实这两个函数用起来倒不是很难,也就是malloc()之后觉得用够了就甩了它把它给free()了,举个简单例子: 程序代码: // Code... char *Ptr = NULL; Ptr = (char *)malloc(100 * sizeof(char)); if (NULL == Ptr) { exit (1); } gets(Ptr); // code... free(Ptr); Ptr = NULL; // code... 就是这样!当然,具体情况要具体分析以及具体解决。比如说,你定义了一个指针,在一个函数里申请了一块内存然后通过函数返回传递给这个指针,那么也许释放这块内存这项工作就应该留给其他函数了。 3、关于函数使用需要注意的一些地方: A、申请了内存空间后,必须检查是否分配成功。 B、当不需要再使用申请的内存时,记得释放;释放后应该把指向这块内存的指针指向NULL,防止程序后面不小心使用了它。 C、这两个函数应该是配对。如果申请后不释放就是内存泄露;如果无故释放那就是什么也没有做。释放只能一次,如果释放两次及两次以上会 出现错误(释放空指针例外,释放空指针其实也等于啥也没做,所以释放空指针释放多少次都没有问题)。 D、虽然malloc()函数的类型是(void *),任何类型的指针都可以转换成(void *),但是最好还是在前面进行强制类型转换,因为这样可以躲过一 些编译器的检查。 好了!最基础的东西大概这么说!现在进入第二部分: 二、malloc()到底从哪里得来了内存空间: 1、malloc()到底从哪里得到了内存空间?答案是从堆里面获得空间。也就是说函数返回的指针是指向堆里面的一块内存。操作系统中有一个记录空闲内存地址的链表。当操作系统收到程序的申请时,就会遍历该链表,然后就寻找第一个空间大于所申请空间的堆结点,然后就将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。就是这样! 说到这里,不得不另外插入一个小话题,相信大家也知道是什么话题了。什么是堆?说到堆,又忍不住说到了栈!什么是栈?下面就另外开个小部分专门而又简单地说一下这个题外话: 2、什么是堆:堆是大家共有的空间,分全局堆和局部堆。全局堆就是所有没有分配的空间,局部堆就是用户分配的空间。堆在操作系统对进程 初始化的时候分配,运行过程中也可以向系统要额外的堆,但是记得用完了要还给操作系统,要不然就是内存泄漏。 什么是栈:栈是线程独有的,保存其运行状态和局部自动变量的。栈在线程开始的时候初始化,每个线程的栈互相独立。每个函数都有自己的栈,栈被用来在函数之间传递参数。操作系统在切换线程的时候会自动的切换栈,就是切换SS/ESP寄存器。栈空间不需要在高级语言里面显式的分配和释放。 以上的概念描述是标准的描述,不过有个别语句被我删除,不知道因为这样而变得不标准了^_^. 通过上面对概念的描述,可以知道: 栈是由编译器自动分配释放,存放函数的参数值、局部变量的值等。操作方式类似于数据结构中的栈。 堆一般由程序员分配释放,若不释放,程序结束时可能由OS回收。注意这里说是可能,并非一定。所以我想再强调一次,记得要释放!
请登录后再发表评论!
1楼的回答很详细了,参考一下就可以了
请登录后再发表评论!
好多都忘了,1楼说的很详细,参考一下吧,楼主
请登录后再发表评论!c语言里面怎么给一个用malloc申请了动态空间的数组赋值
c语言里面怎么给一个用malloc申请了动态空间的数组赋值
比如说p=(int *)malloc(sizeof(int)*n);那么p就相当于数组p[n]的基地址了,所以对它赋值只要用数组的写法:p[i]=x;就可以了
相关知识等待您来回答
编程领域专家推荐这篇日记的豆列
······

我要回帖

更多关于 c语言数组与指针 的文章

 

随机推荐