malloc、realloc和new你明白了么?
//========================================================================
//TITLE:
// malloc、realloc和new你明白了么?
//AUTHOR:
// norains
//DATE:
// Saturday 05-January-2008
//Environment:
// VS2005 + SDK-WINCE5.0-MIPSII
// EVC + SDK-WINCE5.0-MIPSII
//========================================================================
malloc和realloc是C标准函数,而new是C++的关键字,三者都能动态分配内存.但其中一些有意思的细节,你注意了么?
在开篇之前,我们首先需要明确一个概念,数据存储在内存中是无针对性的,换句话说,内存里面的数据,究竟是解释为字符串还是解释为整数,甚至是一个DWORD值还是一个拥有两个WORD的数值,它都是不知道的.如何解释内存中的数据,只和指向这段内存的指针有关.
我们可以用以下代码验证:
int WINAPI WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
#define MAX_SIZE_MALLOC 8
BYTE *pBuf = (BYTE *)malloc(MAX_SIZE_MALLOC);
memset(pBuf + 0,0x17,1);
memset(pBuf + 1,0x4f,1);
memset(pBuf + 2,0xBA,1);
memset(pBuf + 3,0x4E,1);
memset(pBuf + 4,0x9B,1);
memset(pBuf + 5,0x52,1);
memset(pBuf + 6,0x00,1);
memset(pBuf + 7,0x00,1);
WCHAR *pStr = (WCHAR *) pBuf;
wprintf(L"Wide-String : %s ",pStr);
int *pInt = (int *)pBuf;
for(int i = 0 ; i < MAX_SIZE_MALLOC / sizeof(int); i ++)
{
printf("pInt[%d]: %d ",i,pInt[i]);
}
free(pBuf);
Sleep(1000);
}
知道这个,下面所要说到的例子就好理解了.
假设我们有个WCHAR数组,我们需要在使用之前将其全部置0,如果是静态分配,那则是非常简单:
但如果是用new分配的呢?因为用new动态分配无法初始化,所以我们需要手动置0,可能很多朋友的第一想法是如此:
如果MAX_COUT比较大,那估计耗费在置0的时间上不是小数.其实,我们完全可以采用memset替代这个循环.而用memset最重要的一点是,我们需要知道pszNew新分配的数组占了多大的内存空间.不过,这也非常简单.一个WCHAR占据的内存为sizeof(WCHAR),则MAX_COUNT个为MAX_COUNT * sizeof(WCHAR).所以上面的代码可以用memset改写成:
理解这个内存存储空间后,我们也不难明白将pszNew写到文件中的代码为何如此了:
malloc和new都可以动态分配内存,那在实际中如何取舍?一般来说,如果空间是一次性分配,并且不需要再对已分配内存再次进行大小分配,推荐使用new,否则就应该用malloc.
举个例子比较容易理解.假如我们需要分配一个动态内存保存字符串pszA,然后不久之后又有一个字符串pszB送来,而这时需要在原有的内存基础上再追加pszB.如果采用new分配内存,则代码可能会如此:
...
//这代码段用来存储pszA
//pBuf指向存储的地址
TCHAR *pBuf = new TCHAR[_tcslen(pszA) + 1];
_tcscpy(pBuf,pszA);
...
//下面代码追加pszB
TCHAR *pNew = new TCHAR[_tcslen(pBuf) + _tcslen(pszB) + 1];
_tcscpy(pNew,pBuf);
_tcscat(pNew,pszB);
delete [] pBuf;
pBuf = pNew;
如果pBuf内存是用malloc分配的,因为可以使用realloc在保持原有数据的基础上重新分配内存,故代码显得更为精炼:
既然realloc这么方便,那么可不可以先用new分配内存,然后再用realloc重分配呢?最好不要如此.这点在MSDN中描述得很清楚,如果用new分配的内存只能用delete,相对malloc和realloc也只能用free.那如果用free释放new分配的内存会是一种什么结果呢?C++标准中关于这个行为未定义,也就是说,可能没问题,但也不排除出现异常的可能.所以,我们还是老老实实按照建议行事吧.
虽然接下来的内容看似主题无关,但毕竟还是和内存有千丝万缕的联系,所以在这也多说两句,就当成是文章的结尾吧.
给一个变量赋值,给我们的第一直觉是采用"=",这也是最常用的方法,如果想比较BT,你还可以采用memset.就以文章开头的代码做例子为承接而结束全文吧:
//TITLE:
// malloc、realloc和new你明白了么?
//AUTHOR:
// norains
//DATE:
// Saturday 05-January-2008
//Environment:
// VS2005 + SDK-WINCE5.0-MIPSII
// EVC + SDK-WINCE5.0-MIPSII
//========================================================================
malloc和realloc是C标准函数,而new是C++的关键字,三者都能动态分配内存.但其中一些有意思的细节,你注意了么?
在开篇之前,我们首先需要明确一个概念,数据存储在内存中是无针对性的,换句话说,内存里面的数据,究竟是解释为字符串还是解释为整数,甚至是一个DWORD值还是一个拥有两个WORD的数值,它都是不知道的.如何解释内存中的数据,只和指向这段内存的指针有关.
我们可以用以下代码验证:
int WINAPI WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
#define MAX_SIZE_MALLOC 8
BYTE *pBuf = (BYTE *)malloc(MAX_SIZE_MALLOC);
memset(pBuf + 0,0x17,1);
memset(pBuf + 1,0x4f,1);
memset(pBuf + 2,0xBA,1);
memset(pBuf + 3,0x4E,1);
memset(pBuf + 4,0x9B,1);
memset(pBuf + 5,0x52,1);
memset(pBuf + 6,0x00,1);
memset(pBuf + 7,0x00,1);
WCHAR *pStr = (WCHAR *) pBuf;
wprintf(L"Wide-String : %s ",pStr);
int *pInt = (int *)pBuf;
for(int i = 0 ; i < MAX_SIZE_MALLOC / sizeof(int); i ++)
{
printf("pInt[%d]: %d ",i,pInt[i]);
}
free(pBuf);
Sleep(1000);
}
输出结果如下:
Wide-String : 众人力
pInt[0]: 1320832791
pInt[1]: 21147
同样的的内存,只是因为指向的指针类型不同,所输出的结果迥然各异:因为pStr为WCHAR指针,所以将其解释为字符串,输出"众人力";而pInt为int类型指针,而指向的内存大小恰好等于两个int空间,因此又可以采用数组下标的方式获取数值.
了解内存储存的无针对性之后,下面的内容就简单多了.
首先我们需要知道内存空间的计量单位.一般来说,内存分配函数都是以BYTE(字节)为计量单位,如果我们分配两个BYTE的内存,代码则将是如此:
PVOID pBuf = malloc(2);
知道这个,下面所要说到的例子就好理解了.
假设我们有个WCHAR数组,我们需要在使用之前将其全部置0,如果是静态分配,那则是非常简单:
WCHAR pszNew[MAX_COUNT] = {0};
但如果是用new分配的呢?因为用new动态分配无法初始化,所以我们需要手动置0,可能很多朋友的第一想法是如此:
for(int i = 0; i < MAX_COUNT; i ++)
{
pszNew[i] = 0;
}
{
pszNew[i] = 0;
}
如果MAX_COUT比较大,那估计耗费在置0的时间上不是小数.其实,我们完全可以采用memset替代这个循环.而用memset最重要的一点是,我们需要知道pszNew新分配的数组占了多大的内存空间.不过,这也非常简单.一个WCHAR占据的内存为sizeof(WCHAR),则MAX_COUNT个为MAX_COUNT * sizeof(WCHAR).所以上面的代码可以用memset改写成:
memset(pszNew,0,MAX_COUNT * sizeof(WCHAR));
理解这个内存存储空间后,我们也不难明白将pszNew写到文件中的代码为何如此了:
WriteFile(hFile,pszNew,MAX_COUNT * sizeof(WCHAR),&dwWritten, NULL);
malloc和new都可以动态分配内存,那在实际中如何取舍?一般来说,如果空间是一次性分配,并且不需要再对已分配内存再次进行大小分配,推荐使用new,否则就应该用malloc.
举个例子比较容易理解.假如我们需要分配一个动态内存保存字符串pszA,然后不久之后又有一个字符串pszB送来,而这时需要在原有的内存基础上再追加pszB.如果采用new分配内存,则代码可能会如此:
...
//这代码段用来存储pszA
//pBuf指向存储的地址
TCHAR *pBuf = new TCHAR[_tcslen(pszA) + 1];
_tcscpy(pBuf,pszA);
...
//下面代码追加pszB
TCHAR *pNew = new TCHAR[_tcslen(pBuf) + _tcslen(pszB) + 1];
_tcscpy(pNew,pBuf);
_tcscat(pNew,pszB);
delete [] pBuf;
pBuf = pNew;
如果pBuf内存是用malloc分配的,因为可以使用realloc在保持原有数据的基础上重新分配内存,故代码显得更为精炼:
...
//这代码段用来存储pszA
TCHAR *pBuf = (TCHAR *)malloc((_tcslen(pszA) + 1) * sizeof(TCHAR));
_tcscpy(pBuf,pszA);
...
//下面代码追加pszB
pBuf = realloc(pBuf,(_tcslen(pBuf) + _tcslen(pszB) + 1) * sizeof(TCHAR));
_tcscat(pBuf,pszB);
//这代码段用来存储pszA
TCHAR *pBuf = (TCHAR *)malloc((_tcslen(pszA) + 1) * sizeof(TCHAR));
_tcscpy(pBuf,pszA);
...
//下面代码追加pszB
pBuf = realloc(pBuf,(_tcslen(pBuf) + _tcslen(pszB) + 1) * sizeof(TCHAR));
_tcscat(pBuf,pszB);
既然realloc这么方便,那么可不可以先用new分配内存,然后再用realloc重分配呢?最好不要如此.这点在MSDN中描述得很清楚,如果用new分配的内存只能用delete,相对malloc和realloc也只能用free.那如果用free释放new分配的内存会是一种什么结果呢?C++标准中关于这个行为未定义,也就是说,可能没问题,但也不排除出现异常的可能.所以,我们还是老老实实按照建议行事吧.
虽然接下来的内容看似主题无关,但毕竟还是和内存有千丝万缕的联系,所以在这也多说两句,就当成是文章的结尾吧.
给一个变量赋值,给我们的第一直觉是采用"=",这也是最常用的方法,如果想比较BT,你还可以采用memset.就以文章开头的代码做例子为承接而结束全文吧:
//以下每段代码都等价:
*pBuf = 0x17;
pBuf[0] = 0x17;
memset(pBuf + 0,0x17,1);
*pBuf = 0x17;
pBuf[0] = 0x17;
memset(pBuf + 0,0x17,1);
转自:http://blog.csdn.net/song_0521/archive/2009/09/22/4579596.aspx
C语言中的realloc函数功能用C++怎么实现?
定义一个函数,在里面,一个指针存指向你本来指针的内存,然后delete本来指针,重新分配你后来需要的内存,然后用memcpy这个函数把本来指针的内容存放到新分配的内存中去,然后delete那个临时的指针,然后返回重新定义的指针就可以了