看下面代码(来自vs2005)
深度解析malloc函数: extern "C" _CRTIMP void * __cdecl malloc ( size_t nSize ) { void *res = _nh_malloc_dbg(nSize, _newmode, _NORMAL_BLOCK, NULL, 0);//函数调用,跟进 //#define _NORMAL_BLOCK 1 //_newmode == 0 RTCCALLBACK(_RTC_Allocate_hook, (res, nSize, 0)); return res; } //_nh_malloc_dbg函数 extern "C" void * __cdecl _nh_malloc_dbg ( size_t nSize, int nhFlag, int nBlockUse, const char * szFileName, int nLine ) { void * pvBlk; for (;;) { /* do the allocation */ pvBlk = _heap_alloc_dbg(nSize, nBlockUse, szFileName, nLine); //调用函数_heap_alloc_dbg,跟进 if (pvBlk) { return pvBlk; } if (nhFlag == 0) { errno = ENOMEM; return pvBlk; } /* call installed new handler */ if (!_callnewh(nSize)) { errno = ENOMEM; return NULL; } /* new handler was successful -- try to allocate again */ } } //_heap_alloc_dbg函数 extern "C" void * __cdecl _heap_alloc_dbg( size_t nSize, int nBlockUse, const char * szFileName, int nLine ) { long lRequest; size_t blockSize; int fIgnore = FALSE; _CrtMemBlockHeader * pHead; void *retval=NULL; /* lock the heap */ _mlock(_HEAP_LOCK); __try { /* verify heap before allocation */ if (check_frequency > 0) if (check_counter == (check_frequency - 1)) { _ASSERTE(_CrtCheckMemory()); check_counter = 0; } else check_counter++; lRequest = _lRequestCurr; /* break into debugger at specific memory allocation */ if (_crtBreakAlloc != -1L && lRequest == _crtBreakAlloc) _CrtDbgBreak(); /* forced failure */ if ((_pfnAllocHook) && !(*_pfnAllocHook)(_HOOK_ALLOC, NULL, nSize, nBlockUse, lRequest, (const unsigned char *)szFileName, nLine)) { if (szFileName) _RPT2(_CRT_WARN, "Client hook allocation failure at file %hs line %d./n", szFileName, nLine); else _RPT0(_CRT_WARN, "Client hook allocation failure./n"); } else { /* cannot ignore CRT allocations */ if (_BLOCK_TYPE(nBlockUse) != _CRT_BLOCK && !(_crtDbgFlag & _CRTDBG_ALLOC_MEM_DF)) fIgnore = TRUE; /* Diagnostic memory allocation from this point on */ if (nSize > (size_t)(_HEAP_MAXREQ - nNoMansLandSize - sizeof(_CrtMemBlockHeader))) { _RPT1(_CRT_ERROR, "Invalid allocation size: %Iu bytes./n", nSize); errno = ENOMEM; } else { if (!_BLOCK_TYPE_IS_VALID(nBlockUse)) { _RPT0(_CRT_ERROR, "Error: memory allocation: bad memory block type./n"); } blockSize = sizeof(_CrtMemBlockHeader) + nSize + nNoMansLandSize;//实际内存分配的大小 #ifndef WINHEAP /* round requested size */ blockSize = _ROUND2(blockSize, _GRANULARITY); #endif /* WINHEAP */ RTCCALLBACK(_RTC_FuncCheckSet_hook,(0)); pHead = (_CrtMemBlockHeader *)_heap_alloc_base(blockSize); if (pHead == NULL) { errno = ENOMEM; RTCCALLBACK(_RTC_FuncCheckSet_hook,(1)); } else { /* commit allocation */ ++_lRequestCurr; if (fIgnore) { //这里应该是所有申请的空间了,包括信息节点 pHead->pBlockHeaderNext = NULL; pHead->pBlockHeaderPrev = NULL; pHead->szFileName = NULL; pHead->nLine = IGNORE_LINE; pHead->nDataSize = nSize; pHead->nBlockUse = _IGNORE_BLOCK; pHead->lRequest = IGNORE_REQ; } else { /* keep track of total amount of memory allocated */ _lTotalAlloc += nSize; _lCurAlloc += nSize; if (_lCurAlloc > _lMaxAlloc) _lMaxAlloc = _lCurAlloc; if (_pFirstBlock) _pFirstBlock->pBlockHeaderPrev = pHead; else _pLastBlock = pHead; pHead->pBlockHeaderNext = _pFirstBlock; pHead->pBlockHeaderPrev = NULL; pHead->szFileName = (char *)szFileName; pHead->nLine = nLine; pHead->nDataSize = nSize; pHead->nBlockUse = nBlockUse; pHead->lRequest = lRequest; /* link blocks together */ _pFirstBlock = pHead; } /* fill in gap before and after real block */ //+ pHead 0x003f8250 {pBlockHeaderNext=0x003f8060 pBlockHeaderPrev=0x00000000 szFileName=0x00000000 <错误的指针> ...} _CrtMemBlockHeader * memset((void *)pHead->gap, _bNoMansLandFill, nNoMansLandSize); //+ pHead 0x003f8250 {pBlockHeaderNext=0x003f8060 pBlockHeaderPrev=0x00000000 szFileName=0x00000000 <错误的指针> ...} _CrtMemBlockHeader * memset((void *)(pbData(pHead) + nSize), _bNoMansLandFill, nNoMansLandSize); //>+ pHead 0x003f8250 {pBlockHeaderNext=0x003f8060 pBlockHeaderPrev=0x00000000 szFileName=0x00000000 <错误的指针> ...} _CrtMemBlockHeader * /* fill data with silly value (but non-zero) */ memset((void *)pbData(pHead), _bCleanLandFill, nSize); //+ pHead 0x003f8250 {pBlockHeaderNext=0x003f8060 pBlockHeaderPrev=0x00000000 szFileName=0x00000000 <错误的指针> ...} _CrtMemBlockHeader * RTCCALLBACK(_RTC_FuncCheckSet_hook,(1)); retval=(void *)pbData(pHead); //+ pHead 0x003f8250 {pBlockHeaderNext=0x003f8060 pBlockHeaderPrev=0x00000000 szFileName=0x00000000 <错误的指针> ...} _CrtMemBlockHeader * // retval 0x003f8270 void * } } } } __finally { /* unlock the heap */ _munlock(_HEAP_LOCK); } return retval; }
根据代码,我们可以知道,malloc申请的空间不只是nSize大小,还有一个用来记录以申请空间信息的头,这样,总的大小就是blockSize = sizeof(_CrtMemBlockHeader) + nSize + nNoMansLandSize。这就解释了为什么free的时候只需要传入指针就行。
可以尝试一下代码:
int _tmain(int argc, _TCHAR* argv[]) { int *p=NULL; p=(int*)malloc(sizeof(int)*20); printf("%d/n",*(p-1)); printf("%d/n",*(p-2)); printf("%d/n",*(p-3)); printf("%d/n",*(p-4)); }
*(p-4)的值就是malloc时的size大小。