给指针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开始的内存是以下的一片样子:
00000001 00000010 00000011 00000100 00000101 00000110 00000111 00001000
00001001 00001010 00001011 00001100 00001101 00001110 00001111 00010000
然后我有个指针a,它的值是1000。
如果这个指针是int *a。当我用*a去访问数据的时候,就会返回【00000001 00000010 00000011 00000100】
这些数据。
但是如果这个指针是double *a。当我用*a去访问数据,返回的就是【00000001 00000010 00000011 00000100 00000101 00000110 00000111 00001000】这些数据了。

不过这个指针值可是没有变化的,变化的只是指针类型而已。

======分割线[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;temp=a+11;return *temp;
嗯,大概就是这个样子。

======分割线[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]=参考资料=====
http://blog.csdn.net/hzhzh007/article/details/6424638
http://lionwq.spaces.eepw.com.cn/articles/article/item/18555
http://blog.163.com/hangqiang321@yeah/blog/static/164202800201181453113213/
http://hi.baidu.com/yang_qi168/item/5be27010f1b8421eb88a1a46
http://baike.baidu.com/link?url=w21P6YmZq0LhSqPudbRrOtizrYynV1JzAP_jSNn-fFYzhDmBEQavQgIlXJ7o5nxm

时间: 2024-10-26 05:46:14

给指针malloc分配空间后就等于数组吗?的相关文章

如何让类对象只在栈(堆)上分配空间?

转自:http://blog.csdn.net/hxz_qlh/article/details/13135433 一般情况下,编写一个类,是可以在栈或者堆分配空间.但有些时候,你想编写一个只能在栈或者只能在堆上面分配空间的类.这能不能实现呢?仔细想想,其实也是可以滴. 在C++中,类的对象建立分为两种,一种是静态建立,如A a:另一种是动态建立,如A* ptr=new A:这两种方式是有区别的. 1.静态建立类对象:是由编译器为对象在栈空间中分配内存,是通过直接移动栈顶指针,挪出适当的空间,然后

如何把电脑鼠标指针变成QQ空间的鼠标指针

  首先,我们登陆自己的QQ空间,然后依次点上面的"装扮"."装扮商城"."单品"."装饰"."鼠标"(不会的朋友,请看图哈) 接下来,找自己喜欢的鼠标指针,选择好后,我们就用鼠标右键点击该图案,然后选择"属性"(我选择的是海之鳐,哈哈) 在弹出的属性窗口,我们把地址复制下来.(如图) 接下来,我们就不用管QQ空间了,打开记事本,把刚才复制的鼠标的地址粘贴到记事本或者word中.然后修改

struct-关于结构体指针malloc不够的问题,求教!

问题描述 关于结构体指针malloc不够的问题,求教! 定义了一个结构体类型: typedef struct _tag_str{ char * first; short second; }str ,*pstr; 然后再定义一个结构体 typedef struct _tag_str1{ pstr first; float second; }str1,*pstr1; 定义一个变量 pstr1 strr; 在对strr初始化:strr=(pstr1)malloc(sizeof(str1)), 这样其实

网站急诊:更换空间后301对网站排名的影响

我不得不说我们对网站更换空间没有做充分的准备,我也不得不承认百度对301重定向的反应如此之快.我以前太低估它的效率了,看百度也是在不停的进步.不过这个进步对我造成了无与比拟的痛苦,公司网站也可以说是遭受了SE惩罚的血光之灾.   上个星期五,由于服务器空间的原因,公司网站换了网站空间,正是周末,技术拼命把网站源代码,重新上传等等一大堆,都是为了周末能好好休息.我负责网站SEO方面,网站重新上传到新空间后没有任何问题,我想只是更换空间,处理速度很快,应该没有问题的.我就屁颠屁颠的下班了. 周六晚上

虚拟机增加磁盘空间后SWAP分区不能挂载怎么办?

  解决虚拟机linux增加磁盘空间后SWAP分区不能自动挂载的问题,本文所使用linux为LUBUNTU,不保证适用于其他发行版linux 1.进入linux图形界面,在系统工具里面找到磁盘管理工具,lubutnu的磁盘管理工具就是Disk,打开后鼠标点击swap分区,发现此分区是mot mount状态 2.点击左下齿轮形状的图标,选择第一项format,type选择ext4,格式化完成后进入下一步 3.同样点击齿轮形状的按钮,选择edit partition,type选择为swap 0x82

c#-asp.net网站上传后到主机空间后无法写入access数据库

问题描述 asp.net网站上传后到主机空间后无法写入access数据库 我的主机空间是西部数码的服务器,系统应该是windows server的,网站在本地调试时正常,但是上传到主机后能够读出数据库的内容并在页面显示,但是所有对数据库的更新操作都失败,插入,删除,更新等都转跳到错误页面,但是没有捕获到错误信息.数据库是access文件.请问是否有人遇到过类似状况,请问有什么解决方法? 解决方案 1-检查Access数据文件的访问权限.2-你的程序是以什么用户身份.凭据运行的?是否有对应访问权限

link环境下使用codefirst制作一个《网盘软件》,管理员如何分配空间给用户?

问题描述 link环境下使用codefirst制作一个<网盘软件>,管理员如何分配空间给用户? link环境下使用codefirst制作一个<网盘软件>,管理员如何分配空间给用户? 解决方案 需要定义一个字段表示每个用户拥有多少空间,管理员用一个界面去设置它.

(c语言)利用指向结构的指针先输入数据,后打印数据,为什么会出现打印出来的都是0?

问题描述 (c语言)利用指向结构的指针先输入数据,后打印数据,为什么会出现打印出来的都是0? #include #define MAXFIRST 20 #define MAXLAST 20 #define G_STORE 3 #define A_STRORE 3 #define CSIZE 4 struct name { char first[MAXFIRST]; char last[MAXLAST]; }; struct student{ struct name s_name; float g

智能指针-c++ excel dll 数组输入后如何对数组元素值进行计算?

问题描述 c++ excel dll 数组输入后如何对数组元素值进行计算? 问题是这样的 IDE:visual c++ 2013 community excel:2010 目的:编写excel dll 目前阶段:实现了在excel中单元格输入,单元格输出的函数编写,如a+b 现在想要尝试数组/矩阵输入后,经过一定的计算,以数值输出到单元格,如得到这个数组所有元素的总和之类的. 已知输入 #import "C:Program Files (x86)Common Filesmicrosoft sha