怎么检测内存泄露(请高手进)

flybusflybus 2003-02-28 03:45:32
我会另开帖子给分,无上限(我分很多,问问题又不多,呵呵)

以前我用vc,里面有_DEBUG宏可以用,还可以用测试软件,如BoundCheck等,现在公司要我写测试软件去检查代码(**标准c**)是否有内存泄露,各位老大有什么好经验share吗?还有,对于标准c是否也已经有什么工具可以检测到内存泄露,类似BoundCheck

另外象vc里debug时候可以通过建立的内存分配的数据结构来检查内存泄露,我想用c也一样可以做到,不过我不懂vc里他怎么能指出代码是在哪一行出现内存泄露的,怎么判断出代码行及其内容的?用宏来实现?

另外象c++ test那样的软件可以判断出循环语句是否改变了循环条件来绝对是否是死循环,各位大侠说怎么样知道循环条件是否改变呢?
...全文
944 39 打赏 收藏 转发到动态 举报
写回复
用AI写文章
39 条回复
切换为时间正序
请发表友善的回复…
发表回复
rty 2003-03-08
  • 打赏
  • 举报
回复
实际上你可以参考MS C Run Time Library里的malloc, free etc.

下面是malloc里一段代码,FYI:

blockSize = sizeof(_CrtMemBlockHeader) + nSize + nNoMansLandSize;

#ifndef WINHEAP
/* round requested size */
blockSize = _ROUND2(blockSize, _GRANULARITY);
#endif /* WINHEAP */

pHead = (_CrtMemBlockHeader *)_heap_alloc_base(blockSize);

if (pHead == NULL)
return NULL;

/* 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 */
memset((void *)pHead->gap, _bNoMansLandFill, nNoMansLandSize);
memset((void *)(pbData(pHead) + nSize), _bNoMansLandFill, nNoMansLandSize);

/* fill data with silly value (but non-zero) */
memset((void *)pbData(pHead), _bCleanLandFill, nSize);

return (void *)pbData(pHead);
rty 2003-03-08
  • 打赏
  • 举报
回复
我有自己写的一份memory track 源代码
主要使用双链表实现
ANSI C, 单线程,VC6.0++,win2000

想要的话,留下email address

OstrichFly 2003-03-08
  • 打赏
  • 举报
回复
察看是否改变循环条件:
我能想到的只有:
另写一个代码过滤程序,把原先程序里的循环语句替换成类似如下格式:
for ( int i = 0; i < 100; ++ i )
->
for ( int i = 0, _OLD_i = i;
i < 100;
if ( _OLD_i != i ) error(), ++ i, _OLD_i = i )
不过范围有限。
比如这个就不行:
for ( ;isBreak(); )
Tommy 2003-03-03
  • 打赏
  • 举报
回复
至于行号的确定,就像楼上说的,用__FILE__和__LINE__可以得到。
就像上面代码中:

define AllocMemory(size) \
DebugAllocMemory(size, __FILE__, __LINE__)

这样,在程序中调用AllocMemory的地方,实际调用的是DebugAllocMemory(size, __FILE__, __LINE__),在DebugAllocMemory中就可以记录下调用都的文件名和行号了。

至于说死循环检测,好像没有什么简单的办法。不过在运行的时候很容易就发现了吧?

BTW,最好是用现成的工具,毕竟你再怎么做,也没有别人专门搞这个的做得好啊
Tommy 2003-03-03
  • 打赏
  • 举报
回复
1 内存泄漏的检测一般都是重载(在C中可以是定义一个宏)程序中用到的与内存有关的函数(如malloc、free、realloc之类的),在重载的函数中自己用一个数据结构来跟踪所有已经分配的内存以及已经分配的大小,在free时核对要释放的内存与所分配的是否对应,有没有重复释放,在数据结构中标记一下。在程序时,检查还有没有没有释放的内存(查一下自己的数据结构)就可以知道有没有内存泄漏了。
为了使结果更准确,在分配内存时比请求的大小多一些,将内存填满一个固定的值(VC中用的是0xCD),返回中间的内存。这样,一方面可以找出程序中对没有初始化的变量的使用,另一方面,在释放内存时检查一下分给用户的内存的前后部分是否还是原来填充的值,可以判断出程序有没有访问越界。
另外,在释放内存时可以将内存填充固定的值,而且先不真正释放,每次分配都分配新的内存,这样在程序结束时可以根据已经释放的内存中是否还是你填充的值可以知道程序有没有对已经释放的内存进行访问。

我想到的就是这些,你看看《编程精粹》,MS的,上面有讲到这方面的内容
flybusflybus 2003-03-03
  • 打赏
  • 举报
回复
有简单方法否?标准c中,up!
caosheng 2003-03-03
  • 打赏
  • 举报
回复
学习
flybusflybus 2003-03-03
  • 打赏
  • 举报
回复
谢谢,暂时不结帖,看有什么更高的见解没有,不过我已经准备另开帖给分了
Tommy 2003-03-03
  • 打赏
  • 举报
回复
MSDN上说__FILE__和__LINE__是ANSI C中的。

《编程精粹》的英文版叫《writing solid code》,还有一个名字叫《完美模式设计指南》,作者是Steve Maguire,93年的书了,现在网上能找到
flybusflybus 2003-03-03
  • 打赏
  • 举报
回复
谢谢楼上的,另外我想问__FILE__和__LINE__在标准c中都有吗?我最近都在网吧,没办法试
另外你介绍的《编程精粹》看来是本好书,哪个出版社的?how much :-')
flybusflybus 2003-03-02
  • 打赏
  • 举报
回复
晕。。。我有时间看看,如果有用绝对给分,而且再加,呵呵

不过实现确定代码所在行没有简单的办法吗?
wshcdr 2003-03-02
  • 打赏
  • 举报
回复
gz
whhif 2003-03-02
  • 打赏
  • 举报
回复
这个程序的主要原理是什么呢??
能不能注释一下
cxjddd 2003-03-02
  • 打赏
  • 举报
回复
什么时候可以判定有内存泄漏?
Caoyu015 2003-03-02
  • 打赏
  • 举报
回复
好像是用预定义符号 __LINE__代表所在行,__FILE__代表所在文件。具体编译器不知道一不一样,可以查帮助。
eduhf_123 2003-03-02
  • 打赏
  • 举报
回复
学习ing...
Caoyu015 2003-03-02
  • 打赏
  • 举报
回复
呵呵,我看你那么急就直接copy给你咯, 具体说些什么我那记得,C语言我都丢了快两年了。
^_^
Caoyu015 2003-03-02
  • 打赏
  • 举报
回复
MEMTREE *AddMemNode(MEMTREE **Node,
unsigned long Key,
PAYLOAD *Payload)
{
int Diff = 0;
int ChildIdx = 0;
MEMTREE *Twig = NULL;

assert(Node != NULL);
assert(Payload != NULL);

if(*Node == NULL)
{
*Node = malloc(sizeof **Node);
if(*Node != NULL)
{
Twig = *Node;
Twig->Child[MEM_LEFTCHILD] = NULL;
Twig->Child[MEM_RIGHTCHILD] = NULL;
Twig->Key = Key;
Twig->Payload = *Payload;
}
}
else
{
Twig = *Node;

Diff = MemTrkCmp(Key, Twig->Key);

if(Diff == 0)
{
/* Duplicate Key - error. */
assert(0);
}
else
{
ChildIdx = (Diff > 0);

Twig = AddMemNode(&Twig->Child[ChildIdx],
Key,
Payload);
}
}

return Twig;
}

MEMTREE *FindMemNode(MEMTREE *Node, unsigned long Key)
{
int Diff = 0;
int ChildIdx = 0;

if(Node != NULL)
{
Diff = MemTrkCmp(Key, Node->Key);

if(0 != Diff)
{
ChildIdx = (Diff > 0);
Node = FindMemNode(Node->Child[ChildIdx], Key);
}
}

return Node;
}

int WalkMemTree(MEMTREE *Node,
int (*Function)(const PAYLOAD *, void *),
void *Args)
{
int error = 0;

if(Node != NULL)
{
error = WalkMemTree(Node->Child[MEM_LEFTCHILD],
Function,
Args);
if(error == 0)
{
error = (*Function)(&Node->Payload, Args);
}
if(error == 0)
{
error = WalkMemTree(Node->Child[MEM_RIGHTCHILD],
Function,
Args);
}
}

return error;
}


MEMTREE *FindSmallest(MEMTREE *Node)
{
if (Node == NULL)
return NULL;
else if(Node->Child[MEM_LEFTCHILD] == NULL)
return Node;
else
return FindSmallest(Node->Child[MEM_LEFTCHILD]);
}




int DeleteMemNode(MEMTREE **Node, unsigned long Key)
{
int Deleted = 0;
int Diff = 0;
MEMTREE *Successor = NULL;
MEMTREE *NewTop = NULL;
MEMTREE *TopNode = NULL;

if(*Node != NULL)
{
if((*Node)->Key == Key)
{
/* We need to delete the top node. */

Deleted = 1;
TopNode = *Node;

if(TopNode->Child[MEM_LEFTCHILD] == NULL)
{
if(TopNode->Child[MEM_RIGHTCHILD] == NULL)
{
/* Last entry in tree. Just delete it */
free(TopNode);
*Node = NULL;
}
else
{
/* Just one child, a right child */
*Node = TopNode->Child[MEM_RIGHTCHILD];
free(TopNode);
}
}
else
{
if(TopNode->Child[MEM_RIGHTCHILD] == NULL)
{
/* Just one child, a left child */
*Node = TopNode->Child[MEM_LEFTCHILD];
free(TopNode);
}
else
{
PAYLOAD Payload;
unsigned long LocalKey;

/* Two children. This is the awkward case. */
Successor =
FindSmallest(TopNode->Child[MEM_RIGHTCHILD]);
Payload = Successor->Payload;
LocalKey = Successor->Key;

DeleteMemNode(Node, LocalKey);

memcpy(&TopNode->Payload,
&Payload,
sizeof Payload);

TopNode->Key = LocalKey;
}
}
}
else
{
Diff = (MemTrkCmp(Key, (*Node)->Key) > 0);
Deleted = DeleteMemNode(&(*Node)->Child[Diff], Key);
}
}

return Deleted;
}

void DestroyMemTree(MEMTREE **Node)
{
int i;
if(Node != NULL)
{
if(*Node != NULL)
{
for(i = 0; i < 2; i++)
{
DestroyMemTree(&(*Node)->Child[i]);
}
free(*Node);
*Node = NULL;
}
}
}

#endif


测试程序如下:
#include <stdio.h>
#include <stdlib.h>

#include "memtrack.h"

#define N 128

typedef struct FOO
{
char str[128];
double doub[8];
int i[16];
} FOO;

int main(void)
{
char *a[N] = {0};
int *b[N] = {0};
long *c[N] = {0};
double *d[N] = {0};
FOO *f[N] = {0};

int i;

for(i = 0; i < N; i++)
{
a[i] = AllocMemory(sizeof *a[i]);
b[i] = AllocMemory(4 * sizeof *b[i]);
c[i] = AllocMemory(4 * sizeof *c[i]);
d[i] = AllocMemory(8 * sizeof *d[i]);
f[i] = AllocMemory(sizeof *f[i]);
}

TrackMemory(MEMTRK_REPORT,
0, NULL, 0, NULL, 0);

for(i = 0; i < N; i++)
{
ReleaseMemory(a[i]);
ReleaseMemory(b[i]);
ReleaseMemory(c[i]);
ReleaseMemory(d[i]);
ReleaseMemory(f[i]);
}

TrackMemory(MEMTRK_REPORT,
0, NULL, 0, NULL, 0);

TrackMemory(MEMTRK_DESTROY,
0, NULL, 0, NULL, 0);
return 0;
}


Caoyu015 2003-03-02
  • 打赏
  • 举报
回复
int MemPrintAllocs(const PAYLOAD *p1, void *p2)
{
FILE *fp = p2;

fprintf(fp,
"\n%8p allocated %7u byt%s "
"at Line %5d of File %s.",
p1->Ptr,
(unsigned int)p1->Size,
p1->Size == 1 ? "e " : "es",
p1->LineNumber,
p1->FileName);

return 0;
}

/* If we are allocating, we use Ptr. If we are
* freeing, we should be given a key by the
* calling Debugxxx memory allocation function.
*/
int TrackMemory(MEMTRK_MSG Msg,
unsigned long Key,
void * Ptr,
int Size,
char * FileName,
int LineNumber)
{
int ErrorStatus = 0;
static FILE *fp = NULL;
static unsigned long MemTrackIdx = 0;

PAYLOAD EntryBuilder = {0};
MEMTREE *NodePtr = NULL;
unsigned long ThisKey = 0;
PAYLOAD *EntryFinder = NULL;
ALIGN KeyStore = {0};

static MEMTREE *MemTree = NULL;
static int IveBeenInitialised = 0;
static unsigned long MaxAlloc = 0;
static unsigned long CurrAlloc = 0;

time_t tt = {0};
struct tm *tmt = NULL;

if(!IveBeenInitialised)
{
fp = fopen(MEMTRACK_FILENAME, "w");
if(NULL == fp)
{
fprintf(stderr,
"Can't create file %s\n",
MEMTRACK_FILENAME);
fprintf(stderr,
"Using stdout instead.\n");
fp = stdout;
}
IveBeenInitialised = 1;
}

EntryBuilder.FileName = FileName;
EntryBuilder.LineNumber = LineNumber;

switch(Msg)
{
case MEMTRK_MEMALLOC:
EntryBuilder.Ptr = (char *)Ptr + sizeof(ALIGN);
EntryBuilder.Size = Size;
ThisKey = MemTrackIdx++;
KeyStore.lu = ThisKey;
memcpy(Ptr, &KeyStore, sizeof KeyStore);

if(NULL == AddMemNode(&MemTree,
ThisKey,
&EntryBuilder))
{
fprintf(fp,
"ERROR in debugging code - "
"failed to add node to memory tree.\n");
fflush(fp);
}
else
{
CurrAlloc += Size;
if(CurrAlloc > MaxAlloc)
{
MaxAlloc = CurrAlloc;
}
}

break;
case MEMTRK_MEMFREE:

NodePtr = FindMemNode(MemTree, Key);
if(NULL != NodePtr)
{
EntryFinder = &NodePtr->Payload;
CurrAlloc -= EntryFinder->Size;
if(CurrAlloc < 0)
{
fprintf(fp,
"ERROR: More memory released "
"than allocated!\n");
fflush(fp);
}

DeleteMemNode(&MemTree, Key);
}
else
{
/* Tried to free an entry
* that was never allocated.
*/
fprintf(fp,
"Attempted to free unallocated "
"block %p at Line %d of File %s.\n",
EntryBuilder.Ptr,
EntryBuilder.LineNumber,
EntryBuilder.FileName);
fflush(fp);
}

break;

case MEMTRK_REPORT:

fprintf(fp,
"\nMemory Tracker Report\n");
fprintf(fp,
"---------------------\n\n");

tt = time(NULL);
tmt = localtime(&tt);
if(tmt != NULL)
{
char timebuffer[64] = {0};

strftime(timebuffer,
sizeof timebuffer,
"%H:%M:%S %Z on %A %d %B %Y",
tmt);
fprintf(fp, "\n%s\n\n", timebuffer);
}

fprintf(fp,
"Current Allocation: %lu byt%s.\n",
CurrAlloc,
CurrAlloc == 1 ? "e" : "es");

fprintf(fp,
"Maximum Allocation: %lu byt%s.\n",
MaxAlloc,
MaxAlloc == 1 ? "e" : "es");

fprintf(fp,
"Nodes currently allocated:\n\n");

WalkMemTree(MemTree, MemPrintAllocs, fp);
if(CurrAlloc == 0)
{
fprintf(fp, "None! (Well done!)");
}
fprintf(fp, "\n");
fflush(fp);
break;
case MEMTRK_DESTROY:
DestroyMemTree(&MemTree);
if(ferror(fp))
{
fprintf(stderr, "Error writing to log file.\n");
}
fclose(fp);
break;
default:
break;
}

return ErrorStatus;
}

/* Binary search tree functions
*
* Many thanks to Ben Pfaff, for the help he gave me on
* node deletions - his name will be forever etched into
* the bark of any tree you care to grow using
* this source. If you want /real/ trees, though, have a
* look at Ben's chapter on AVL and red-black trees.
*
* I'd also like to thank Chad Dixon for the all-night
* debugging session he suffered in a (successful!)
* attempt to get this code to work.
*
*/
Caoyu015 2003-03-02
  • 打赏
  • 举报
回复
好像《 标准C语言实用大全 》上面有一个类似于这种问题的解决方案。大概的原理我记得是一样的。我现在给书上的代码给你 它主要是一个用于跟踪内存
头文件如下:
/----------------- MEMTRACK.H ----------------------/

#ifndef MEMTRACK_H__
#define MEMTRACK_H__

#define MEMTRACK_FILENAME "MEMTRACK.TXT"

#ifdef MEMTRACK

#define AllocMemory(size) \
DebugAllocMemory(size, __FILE__, __LINE__)

#define AllocCopyString(s) \
DebugAllocCopyString(s, __FILE__, __LINE__)

#define ReAllocMemory(p, newsize) \
DebugReAllocMemory(p, newsize, __FILE__, __LINE__)

#define ReleaseMemory(p) \
DebugReleaseMemory(p, __FILE__, __LINE__)

#define MEMTRK_MEMALLOC 1
#define MEMTRK_MEMFREE 2
#define MEMTRK_REPORT 3
#define MEMTRK_DESTROY 4

#ifndef TYP_MEMTRK_MSG
#define TYP_MEMTRK_MSG

typedef int MEMTRK_MSG;

#endif

#ifndef TYP_ALIGN
#define TYP_ALIGN

typedef union
{
long l; /* if C99, consider using intmax_t instead */
unsigned long lu;
double f;
long double lf;
void *vp;
void (*fp)(void);
} ALIGN;

#endif

#ifndef TYP_PAYLOAD
#define TYP_PAYLOAD

typedef struct PAYLOAD
{
void *Ptr;
size_t Size;
char *FileName;
int LineNumber;
} PAYLOAD;

#endif

#define MEM_LEFTCHILD 0
#define MEM_RIGHTCHILD 1
#define MEM_MAX_CHILDREN 2

#ifndef TYP_MEMTREE
#define TYP_MEMTREE

typedef struct MEMTREE
{
struct MEMTREE *Child[MEM_MAX_CHILDREN];
unsigned long Key;
PAYLOAD Payload;
} MEMTREE;

#endif

void *DebugAllocMemory(size_t Size,
char *FileName,
int LineNumber);

char *DebugAllocCopyString(char *String,
char *FileName,
int LineNumber);

void *DebugReAllocMemory(void *pOldMem,
size_t NewSize,
char *FileName,
int LineNumber);

void DebugReleaseMemory(void *ppSource,
char *FileName,
int LineNumber);

int MemPrintAllocs(const PAYLOAD *p1,
void *p2);

int TrackMemory(MEMTRK_MSG Msg,
unsigned long Key,
void *Ptr,
int Size,
char *FileName,
int LineNumber);


MEMTREE *AddMemNode(MEMTREE **Node,
unsigned long Key,
PAYLOAD *Payload);

MEMTREE *FindMemNode(MEMTREE *Node,
unsigned long Key);

int DeleteMemNode(MEMTREE **Node,
unsigned long Key);

int WalkMemTree(MEMTREE *Node,
int (*Func)(const PAYLOAD *, void *),
void *Args);

void DestroyMemTree(MEMTREE **Node);

#else
#define AllocMemory malloc
#define AllocCopyString CopyString
#define ReAllocMemory realloc
#define ReleaseMemory free
#define TrackMemory(a, b, c, d, e, f)

#endif

char *CopyString(char *InString);

#endif

/---------------MEMTRACK.C--------------------------------------/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include <assert.h>

#include "memtrack.h"

/* portable implementation of strdup().
* Allocates sufficient memory to make a copy
* of a string, and then copies that string.
* Returns a pointer to the new string, or
* NULL (when there is insufficient memory or
* when the parameter is NULL).
*/
char *CopyString(char *InString)
{
char *p = NULL;

if(InString != NULL)
{
p = malloc(strlen(InString) + 1);
if(NULL != p)
{
strcpy(p, InString);
}
}

return p;
}

#ifdef MEMTRACK

/* Tracking versions */

void *DebugAllocMemory(size_t Size,
char *FileName,
int LineNumber)
{
void *ptr;
char *p;

ptr = malloc(Size + sizeof(ALIGN));
if(ptr != NULL)
{
TrackMemory(MEMTRK_MEMALLOC,
0,
ptr,
Size,
FileName,
LineNumber);

/* To disguise our little hideyhole, we need to report
* an address sizeof(ALIGN) bytes higher than the one
* returned by malloc. But we can't do pointer
* arithmetic on void pointers. So we use a temporary
* char *.
*/
p = ptr;
p += sizeof(ALIGN);
ptr = p;
}

return ptr;
}

char *DebugAllocCopyString(char *String,
char *FileName,
int LineNumber)
{
char *p = NULL;
int ErrorStatus = 0;
size_t Length = strlen(String) + 1;

p = malloc(Length + sizeof(ALIGN));
if(0 == ErrorStatus)
{
strcpy(p + sizeof(ALIGN), String);
TrackMemory(MEMTRK_MEMALLOC,
0,
p,
Length,
FileName,
LineNumber);

p += sizeof(ALIGN);
}
return p;
}


void *DebugReAllocMemory(void *pOldMem,
size_t NewSize,
char *FileName,
int LineNumber)
{
void *NewPtr = NULL;
int ItWasntNull = 0;
char *p;

ALIGN KeyStore;

if(pOldMem != NULL)
{
ItWasntNull = 1;

p = pOldMem;

p -= sizeof(ALIGN);

memcpy(&KeyStore.lu, p, sizeof(ALIGN));
}

NewPtr = realloc(pOldMem,
NewSize +
(NewSize > 0 ?
sizeof(ALIGN) :
0));

if(NULL != NewPtr)
{
if(ItWasntNull)
{
TrackMemory(MEMTRK_MEMFREE,
KeyStore.lu,
NULL,
0,
FileName,
LineNumber);
}

if(NewSize > 0)
{
TrackMemory(MEMTRK_MEMALLOC,
0,
NewPtr,
NewSize,
FileName,
LineNumber);

p = NewPtr;
p += sizeof(ALIGN);
NewPtr = p;
}
}

return NewPtr;
}

void DebugReleaseMemory(void *pSource,
char *FileName,
int LineNumber)
{
char *p;
ALIGN KeyStore;

if(pSource != NULL)
{
p = pSource;
p -= sizeof(ALIGN);
memcpy(&KeyStore.lu, p, sizeof(ALIGN));

TrackMemory(MEMTRK_MEMFREE,
KeyStore.lu,
NULL,
0,
FileName,
LineNumber);

free(p);
}
}

/* Our first hash just gives us a /relatively/
* well-balanced tree. It isn't going to
* give us much uniqueness.
*/
unsigned long hash1(unsigned long value)
{ /* N1 P1 K1 */
return ((value * 179424601UL + 71UL) % 167UL);
}

/* This second hash gives us a guarantee of uniqueness
* over a relatively large number of keys -
* 2147483647 keys, in fact. If this isn't enough for
* you, consider using a C99 compiler, specifying K1
* as long long, and setting it to some prime number
* about halfway between 2^63 and 2^64.
*/
unsigned long hash2(unsigned long value)
{ /* N1 P1 K1 */
return ((value * 179424673UL + 257UL) % 2147483647UL);
}

int MemTrkCmp(unsigned long key1,
unsigned long key2)
{
int diff = 0;

unsigned long hv1, hv2;

hv1 = hash1(key1);
hv2 = hash1(key2);

if(hv1 > hv2)
{
diff = 1;
}
else if(hv1 < hv2)
{
diff = -1;
}
else
{
hv1 = hash2(key1);
hv2 = hash2(key2);
if(hv1 > hv2)
{
diff = 1;
}
else if(hv1 < hv2)
{
diff = -1;
}
else
{
assert(key1 == key2);
}
}

return diff;
}

加载更多回复(19)

69,374

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧