vc中常用到的几个内存分配c语言中用什么函数分配内存

C++内存分配秘籍_百度文库
您的浏览器Javascript被禁用,需开启后体验完整功能,
享专业文档下载特权
&赠共享文档下载特权
&10W篇文档免费专享
&每天抽奖多种福利
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
C++内存分配秘籍
&&C++内存分配秘籍
你可能喜欢VC sizeof(struct)内存分配分析
我的图书馆
VC sizeof(struct)内存分配分析
sizeof使用介绍&&本文主要包括二个部分,第一部分重点介绍在VC中,怎么样采用sizeof来求结构的大小,以及容易出现的问题,并给出解决问题的方法,第二部分总结出VC中sizeof的主要用法。&&1、sizeof应用在结构上的情况&&请看下面的结构:&&struct&& MyStruct&&{&&double&& d1;&&char&& d2;&&int&& in&&};&&对结构MyStruct采用sizeof会出现什么结果呢?
sizeof(MyStruct)为多少呢?也许你会这样求:&&sizeof(MyStruct)=sizeof(double)+sizeof(char)+sizeof(int)=13&&但是当在VC中测试上面结构的大小时,会发现sizeof(MyStruct)为16。
其实,这是VC对变量存储的一个特殊处理。为了提高CPU的存储速度,VC对一些变量的起始地址做了“对齐”处理。在默认情况下,VC规定各成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数。下面列出常用类型的对齐方式(vc6.0,32位系统)。&&类型&& 对齐方式(变量存放的起始地址相对于结构的起始地址的偏移量)&&char&&& 偏移量必须为sizeof(char)即1的倍数&&int&&&&&偏移量必须为sizeof(int)即4的倍数&&float&&&偏移量必须为sizeof(float)即4的倍数&&double&&偏移量必须为sizeof(double)即8的倍数&&Short&&&偏移量必须为sizeof(short)即2的倍数&&各成员变量在存放的时候根据在结构中出现的顺序依次申请空间,同时按照上面的对齐方式调整位置,空缺的字节VC会自动填充。同时VC为了确保结构的大小为结构的字节边界数(即该结构中占用最大空间的类型所占用的字节数)的倍数,所以在为最后一个成员变量申请空间后,还会根据需要自动填充空缺的字节。&&下面用前面的例子来说明VC到底怎么样来存放结构的。&&struct&& MyStruct&&&&{&&double&& d1;&&&&char&& d2;&&int&&};&&为上面的结构分配空间的时候,VC根据成员变量出现的顺序和对齐方式,先为第一个成员d1分配空间,其起始地址跟结构的起始地址相同(刚好偏移量0刚好为 sizeof(double)的倍数),该成员变量占用sizeof(double)=8个字节;接下来为第二个成员d1分配空间,这时下一个可以分配的地址对于结构的起始地址的偏移量为8,是sizeof(char)的倍数,所以把d1存放在偏移量为8的地方满足对齐方式,该成员变量占用sizeof (char)=1个字节;接下来为第三个成员in分配空间,这时下一个可以分配的地址对于结构的起始地址的偏移量为9,不是sizeof(int)=4的倍数,为了满足对齐方式对偏移量的约束问题,VC自动填充3个字节(这三个字节没有放什么东西),这时下一个可以分配的地址对于结构的起始地址的偏移量为 12,刚好是sizeof(int)=4的倍数,所以把type存放在偏移量为12的地方,该成员变量占用sizeof(int)=4个字节;这时整个结构的成员变量已经都分配了空间,总的占用的空间大小为:8+1+3+4=16,刚好为结构的字节边界数(即结构中占用最大空间的类型所占用的字节数 sizeof(double)=8)的倍数,所以没有空缺的字节需要填充。所以整个结构的大小为:sizeof(MyStruct)=8+1+3+4= 16,其中有3个字节是VC自动填充的,没有放任何有意义的东西。&&
下面再举个例子,交换一下上面的MyStruct的成员变量的位置,使它变成下面的情况:
struct MyStruct&& {&& && double dda1; &&&& };
这个结构占用的空间为多大呢?在VC6.0环境下,可以得到sizeof(MyStruc)为24。结合上面提到的分配空间的一些原则,分析下VC怎么样为上面的结构分配空间的。(简单说明)struct MyStruct {
double dda1;
int type;
&&& 所有成员变量都分配了空间,空间总的大小为1+7+8+4=20,不是结构的节边界数(即结构中占用最大空间的基本数据类型所占用的字节数sizeof(double)=8)的倍数,所以需要填充4个字节,以满足结构的大小为sizeof(double)=8的倍数。&& 所以该结构总的大小为:sizeof(MyStruc)为1+7+8+4+4=24。其中总的有7+4=11个字节是VC自动填充的,没有放任何有意义的东西。
typedef struct { int k[5]; char d[5];} DATE;struct data { DATE};DATEint a = sizeof(max);// 40int nDataSize = sizeof(data);// 56
VC对结构的存储的特殊处理确实提高CPU存储变量的速度,但是有时候也带来了一些麻烦,我们也屏蔽掉变量默认的对齐方式,自己可以设定变量的对齐方式。&&VC中提供了#pragma&& pack(n)来设定变量以n字节对齐方式。n字节对齐就是说变量存放的起始地址的偏移量有两种情况:
第一、如果n大于等于该变量所占用的字节数,那么偏移量必须满足默认的对齐方式(不用满足n对齐方式)&;& 第二、如果n小于该变量的类型所占用的字节数,那么偏移量为n的倍数(不用满足默认的对齐方式)。
结构的总大小也有个约束条件,分下面两种情况:如果n大于所有成员变量类型所占用的字节数,那么结构的总大小必须为占用空间最大的变量占用的空间数的倍数; 否则必须为n的倍数。
#pragma pack(n)它指定了结构成员按n(1,2,4,8,16)字节对齐,如果未指定n即#pragma pack(),则恢复成默认值。
当n大于结构体或类等的最大字节那个变量的字节时,n就等于最大字节的那个变量的字节,结构体或类的总字节数必须为n的整数倍(就如没用#pragma pack (n)时结构体或类的总字节数必须为最大字节变量的字节的整数被)
下面举例说明其用法。&&#pragma&& pack(push)&& //保存对齐状态&&#pragma&& pack(4)//设定为4字节对齐&&struct&& test&&{&&char&& m1;&&double&& m4;&&int&& m3;&&};&&#pragma&& pack(pop)//恢复对齐状态&&以上结构的大小为16,下面分析其存储情况,首先为m1分配空间,其偏移量为0,满足我们自己设定的对齐方式(4字节对齐),m1占用1个字节。接着开始为m4分配空间,这时其偏移量为1,需要补足3个字节,这样使偏移量满足为n=4的倍数(因为sizeof(double)大于n),m4占用8个字节。接着为m3分配空间,这时其偏移量为12,满足为4的倍数,m3占用4个字节。这时已经为所有成员变量分配了空间,共分配了16个字节,满足为n的倍数。如果把上面的#pragma&& pack(4)改为#pragma&& pack(16),那么我们可以得到结构的大小为24。
2、&& sizeof用法总结&&在VC中,sizeof有着许多的用法,而且很容易引起一些错误。下面根据sizeof后面的参数对sizeof的用法做个总结。&&A.&& 参数为数据类型或者为一般变量。例如sizeof(int),sizeof(long)等等。这种情况要注意的是不同系统系统或者不同编译器得到的结果可能是不同的。例如int类型在16位系统中占2个字节,在32位系统中占4个字节。&&B.&& 参数为数组或指针。下面举例说明.&&int&& a[50];&& //sizeof(a)=4*50=200;&& 求数组所占的空间大小&&int&& *a=new&& int[50];//&& sizeof(a)=4;&& a为一个指针,sizeof(a)是求指针&&//的大小,在32位系统中,当然是占4个字节。&&C.&& 参数为结构或类。Sizeof应用在类和结构的处理情况是相同的。但有两点需要注意,第一、结构或者类中的静态成员不对结构或者类的大小产生影响,因为静态变量的存储位置与结构或者类的实例地址无关。&&第二、没有成员变量的结构或类的大小为1,因为必须保证结构或类的每一个实例在内存中都有唯一的地址。&&下面举例说明,&&Class&& Test{int&&static&& double&& c};//sizeof(Test)=4.&&Test&& *s;//sizeof(s)=4,s为一个指针。&&Class&& test1{&& };//sizeof(test1)=1;&&D.&& 参数为其他。下面举例说明。&&int&& func(char&& s[5]);&&{&&//sizeof(s)这里将输出4,本来s为一个数组,
//但由于做为函数的参数在传递的时候系统处理为一个指针,所以sizeof(s)实际上为求指针的大小。&&return&& 1;&&}&&sizeof(func(&#&#8221;))=4//因为func的返回类型为int,所以相当于&&//求sizeof(int). <img title="VC&sizeof(struct)内存分配分析" border=0 alt="VC&sizeof(struct)内存分配分析" src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=0441787&page=RSS%3a+sizeof%e4%bd%bf%e7%94%a8%e4%bb%8b%e7%bb%8d&referrer=" width=1 height=1 src_cetemp="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=0441787&page=RSS%3a+sizeof%e4%bd%bf%e7%94%a8%e4%bb%8b%e7%bb%8d&referrer=" real_src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=0441787&page=RSS%3a+sizeof%e4%bd%bf%e7%94%a8%e4%bb%8b%e7%bb%8d&referrer=">
[转]&[转]&[转]&[转]&[转]&[转]&
喜欢该文的人也喜欢VC++常用分配内存函数简介及比较
VC++常用分配内存函数简介及比较
1. 首先我们来看HeapAlloc:MSDN上的解释为:HeapALloc是从堆上分配一块内存,且分配的内存是不可移动的(即如果没有连续的空间能满足分配的大小,程序不能将其他零散的 空间利用起来,从而导致分配失败),该分配方法是从一指定地址开始分配,而不像GloabalAlloc是从全局堆上分配,这个有可能是全局,也有可能是 局部。函数原型为:LPVOIDHeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes);hHeap是进程堆内存开始位置。dwFlags是分配堆内存的标志。包括HEAP_ZERO_MEMORY,即使分配的空间清零。dwBytes是分配堆内存的大小。其对应的释放空间函数为HeapFree。2. 再看GlobalAlloc:该函数用于从全局堆中分配出内存供程序使用,函数原型为:HGLOBAL GlobalAlloc(UINT uFlags, SIZE_T dwBytes);uFlags参数含义GHND
GMEM_MOVEABLE和GMEM_ZEROINIT的组合GMEM_FIXED
分配固定内存,返回值是一个指针GMEM_MOVEABLE
分配活动内存,在Win32中,内存块不能在物理内存中移动,但能在默认的堆中移动。返回值是内存对象的句柄,用函数GlobalLock可将句柄转化为指针GMEM_ZEROINIT
将内存内容初始化为零GPTR
GMEM_FIXED和GMEM_ZEROINIT的组合一般情况下我们在编程的时候,给应用程序分配的内存都是可以移动的或者是可以丢弃的,这样能使有限的内存资源充分利用,所以,在某一个时候我们分配的那块 内存的地址是不确定的,因为他是可以移动的,所以得先锁定那块内存块,这儿应用程序需要调用API函数GlobalLock函数来锁定句柄。如下: lpMem=GlobalLock(hMem); 这样应用程序才能存取这块内存。所以我们在使用GlobalAllock时,通常搭配使用GlobalLock,当然在不使用内存时,一定记得使用 GlobalUnlock,否则被锁定的内存块一直不能被其他变量使用。GlobalAlloc对应的释放空间的函数为GlobalFree。3. LocalAlloc:该函数用于从局部堆中分配内存供程序使用,函数原型为:HLOCAL LocalAlloc(UINT uFlags, SIZE_T uBytes);参数同GlobalAlloc。在16位Windows中是有区别的,因为在16位windows用一个全局堆和局部堆来管理内存,每一个应用程序或dll装入内存时,代码段被装入全局 堆,而系统又为每个实例从全局堆中分配了一个64kb的数据段作为该实例的局部堆,用来存放应用程序的堆栈和所有全局或静态变量。而 LocalAlloc/GlobalAlloc就是分别用于在局部堆或全局堆中分配内存。 由于每个进程的局部堆很小,所以在局部堆中分配内存会受到空间的限制。但这个堆是每个进程私有的,相对而言分配数据较安全,数据访问出错不至于影响到整个系统。 而在全局堆中分配的内存是为各个进程共享的,每个进程只要拥有这个内存块的句柄都可以访问这块内存,但是每个全局内存空间需要额外的内存开销,造成分配浪费。而且一旦发生严重错误,可能会影响到整个系统的稳定。 不过在Win32中,每个进程都只拥有一个省缺的私有堆,它只能被当前进程访问。应用程序也不可能直接访问系统内存。所以在Win32中全局堆和局部堆都 指向进程的省缺堆。用LocalAlloc/GlobalAlloc分配内存没有任何区别。甚至LocalAlloc分配的内存可以被 GlobalFree释放掉。所以在Win32下编程,无需注意Local和Global的区别,一般的内存分配都等效于 HeapAlloc(GetProcessHeap(),...)。LocalAlloc对应的释放函数为LockFree。4. VirtualAlloc:该函数的功能是在调用进程的虚地址空间,预定或者提交一部分页,如果用于内存分配的话,并且分配类型未指定MEM_RESET,则系统将自动设置为0;其函数原型:LPVOID VirtualAlloc(LPVOID lpAddress, // region to reserve or commitSIZE_T dwSize, // size of regionDWORD flAllocationType, // type of allocationDWORD flProtect // type of access protection);VirtualAlloc可以通过并行多次调用提交一个区域的部分或全部来保留一个大的内存区域。多重调用提交同一块区域不会引起失败。这使得一个应用程 序保留内存后可以随意提交将被写的页。当这种方式不在有效的时候,它会释放应用程序通过检测被保留页的状态看它是否在提交调用之前已经被提交。VirtualAlloc对应的释放函数为VirtualFree。5.Malloc:malloc与free是C++/C语言的标准库函数,可用于申请动态内存和释放内存。对于非内部数据类型的对象而言,光用 malloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是 库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。6.New:new/delete是C++的运算符。可用于申请动态内存和释放内存。C++语言需要一个能完成动态内存分配和初始化工作的运算符new, 以一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。C++程序经常要调用C函数,而C程序只能用malloc /free管理动态内存。new 是个操作符,和什么"+","-","="...有一样的地位. malloc是个分配内存的函数,供你调用的. new是保留字,不需要头文件支持. malloc需要头文件库函数支持.new 建立的是一个对象, malloc分配的是一块内存. new建立的对象你可以把它当成一个普通的对象,用成员函数访问,不要直接访问它的地址空间 malloc分配的是一块内存区域,就用指针访问好了,而且还可以在里面移动指针.内存泄漏对于malloc或者new都可以检查出来的,区别在于new可以指明是那个文件的那一行,而malloc没有这些信息。new可以认为是 malloc加构造函数的执行。new出来的指针是直接带类型信息的。而malloc返回的都是void指针。
vs2010 vc++ malloc分配内存
内存操作函数
vc之内存操作函数
没有更多推荐了,  目前正在学习C++中,对于C++的类及其类的实现原理也挺感兴趣。于是打算通过观察类在内存中的分布更好地理解类的实现。因为其实类的分布是由编译器决定的,而本次试验使用的编译器为VS2015 RC,其编译环境为VC++,这里感谢@&提醒。所以此处的标题为《VC++中的类的内存分布》。因为博主可能比较懒,所以把这个知识点分作两次写。( ╯□╰ )。
1.对无虚函数类的探索
  1.1 空类
  我们先一步一步慢慢来,从一个空的类开始。
class test
int main(int argc, char *argv[])
cout && sizeof(ts) &&
  结果输出的是1。
  于是我们推测,对于一个空类,内存总会为其分配一个字节的空间。为此,我们可以来验证一下:
int main(int argc, char *argv[])
char ch = '0';
int a1, a2;
a1 = (int)(&ts);
a2 = (int)(&ts + 1);
memcpy(&ts, &ch, 1);
cout && sizeof(ts) &&
  可以看到,a1为ts的地址(强制转化为int),a2为ts的下一个地址,然后我们去内存那里看一下
  结果真的把ch里面的内容写入到ts中了。
  综上可以得出一个结论,对于一个空类,编译器总会为其分配一个字节的内存。
  1.2 仅含数据成员的类
  首先对于数据成员为一个字节(char)的类,通过上述的测试代码,结果和空类一样,编译器分配了一个字节的空间给了类中的char。这是在我们的预料之内的事。
  可是当我们的类设计成含有不同类型的数据结构的时候,结果就不同了:
class test
  程序的输出结果是8。可以看到,此时类占用内存的空间是8个字节。
  这就涉及到&内存对齐&了。所以接下来我们就先来探讨一下C++里的&内存对齐&。
内存对齐:
  对于一个类(结构体),编译器为了提高内存读取速率以及可移植性,存在一种称作为&内存对齐&的规则。一般对于内存对齐,编译器会帮你完成,但是这种工作其实是可以由编程者自己完成的。
  C++中,可以使用#pragma pack(n)的预编译处理进行设置&对齐系数&。(这个对齐系数在VC中一般默认为8。)
  为了能够更好地了解内存中内存对齐的流程,我特地画了分配空间的流程图。(仅本人自己理解,如有谬误请各位大侠指出。)
  下面我们通过实例来说明一下内存对齐。(在这里先只考虑数据成员不为类(结构体)的情况)
class test
  虽然类的内容一样,但是会因为对齐系数n的不同,内存中的分配也会有所不同。下图能够比较形象地说明,其中,红色表示char型,蓝色标识int型,绿色表示short型。图中的列数是根据min(max(结构体中的数据类型),n)确定的。  (1)例子1:pragma pack(1)
  (2)例子2:pragma pack(2)
  (3)例子3:pragma pack(4)
  可以看到,不同的对齐系数会使内存的分布呈现不同的格局。
  讨论完内存对齐之后,我们来看一看类中的static成员。
类中的static成员:
  我们设计一个这样的类,类中包括有静态数据成员。
class test
  结果我们发现,该类的大小还是和之前无异。
  同时,我们通过cout语句查看类中的static成员地址。
cout && sizeof(ts) && '\n' && (int)&ts.si && '\n' && (int)(&ts) &&
  结果得出的类的地址和类的static成员的地址相差十万八千里。显而易见,类中的static成员并不是和类储存在一起的。
  综上可以得到的结论是:类中的成员数据中,仅有非static成员数据才会为其开辟内存空间。
  1.3 包含成员函数的类
  这里要先感谢一下@melonstreet 提到的问题,已改正。
  对于类中的成员函数,我们知道,对于所有类,每个成员函数都只有一个副本。函数代码是存储在对象空间之外的。如果对同一个类定义了10个对象,这些对象的成员函数对应的是同一个函数代码段,而不是10个不同的函数代码段。在这里,关于具体到对象的成员函数是如何调用的,我们有两种猜想:第一种猜想是每一个对象中都必须开辟一段内存,用来存储指向类中的成员函数的指针,每次当外部对对象的成员函数进行调用的时候,通过访问对象空间中的函数指针从而访问函数。第二种猜想是类中的成员函数是独立出来的,每个对象中并没有储存成员函数的相关信息,而成员函数的调用是通过编译器在编译的时候自动帮我们选择要访问的函数。为此,我们也要进行一些测试。
class test
static int
test():c('0'),i(0),s(0) {};
void print(void) { cout && sizeof(test) && '\n' && (int)&si && '\n' && (int)this && }
  输出结果显示内存仍然不变,说明成员函数在类的内存中并不占空间。
  综上可以得出结论:对于无继承的类的成员函数,是独立出来的,类的内存中并没有存储相应的函数信息。对于成员函数的访问,是通过编译器完成的。
可是,在这里,我们少考虑了一种情况:虚函数的存在。这是一种特例,内存将会为其分配相应空间。在这里先不做讨论,且看下篇的具体分析。
阅读(...) 评论()VC下如何分配大块内存?在线等待
[问题点数:100分,结帖人Land3000]
本版专家分:17
结帖率 100%
CSDN今日推荐
本版专家分:17016
本版专家分:993
本版专家分:17
本版专家分:17
匿名用户不能发表回复!|
其他相关推荐

我要回帖

更多关于 c语言内存分配函数 的文章

 

随机推荐