【发布时间】:2012-10-14 16:20:58
【问题描述】:
我将在此处发布(我认为)与问题相关的代码的 sn-ps,但如有必要,我可以粘贴 bin。可能已经发布了足够多的代码:P
我的程序包含一个哈希表,当某个哈希桶达到 20 个条目时,该哈希表需要加倍。虽然我相信逻辑很好,而且它像魅力一样编译,但它抛出了一个 Segmentation Fault。代码在不调整大小时运行起来就像一个魅力,但调整大小却把事情搞砸了。
感谢您的帮助:)
错误
Program received signal SIGSEGV, Segmentation fault.
0x0000000000401012 in ml_add (ml=0x7fffffffe528, me=0x75a5a0) at mlist.c:74
74 while((cursorNode->next) != NULL){
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.80.el6_3.5.x86_64
(gdb) backtrace
#0 0x0000000000401012 in ml_add (ml=0x7fffffffe528, me=0x75a5a0) at mlist.c:74
#1 0x0000000000401554 in main (argc=1, argv=0x7fffffffe638) at finddupl.c:39
哈希表的结构
typedef struct bN { //linked list node containing data and next
MEntry *nestedEntry;
struct bN *next;
} bucketNode;
typedef struct bL { // bucket as linked list
struct bN *first;
int bucketSize;
} bucket;
struct mlist {
struct bL *currentTable; //bucket array
};
添加功能
int ml_add(MList **ml, MEntry *me){
MList *tempList;
tempList = *ml;
bucketNode *tempNode = (bucketNode *)malloc(sizeof(bucketNode));
tempNode->nestedEntry = me;
tempNode->next = NULL;
unsigned long currentHash = me_hash(me, tableSize);
if((tempList->currentTable[currentHash].bucketSize) == 0) {
tempList->currentTable[currentHash].first = tempNode;
tempList->currentTable[currentHash].bucketSize = (tempList->currentTable[currentHash].bucketSize) + 1;
}
else if((tempList->currentTable[currentHash].bucketSize) == 20){
printf("About to resize");
printf("About to resize");
tempList = ml_resize(&tempList, (tableSize * 2));
tableSize = tableSize * 2;
ml_add(&tempList,me);
}
else{
bucketNode *cursorNode;
cursorNode = tempList->currentTable[currentHash].first;
while((cursorNode->next) != NULL){
cursorNode = cursorNode->next;
}
cursorNode->next = tempNode;
tempList->currentTable[currentHash].bucketSize = (tempList->currentTable[currentHash].bucketSize) + 1;
return 1;
}
return 1;
}
调整大小功能
MList *ml_resize(MList **ml, int newSize){
MList *oldList;
oldList = *ml;
MList *newList;
if ((newList = (MList *)malloc(sizeof(MList))) != NULL){
newList->currentTable = (bucket *)malloc(newSize * sizeof(bucket));
int i;
for(i = 0; i < newSize; i++){
newList->currentTable[i].first = NULL;
newList->currentTable[i].bucketSize = 0;
}
}
int j;
for(j = 0; j < tableSize; j++){
bucketNode *cursorNode = oldList->currentTable[j].first;
bucketNode *nextNode;
while(cursorNode != NULL){
nextNode = cursorNode->next;
ml_transfer(&newList, cursorNode, newSize);
cursorNode = nextNode;
}
}
free(oldList);
return newList;
}
转移到新列表功能
void ml_transfer(MList **ml, bucketNode *insertNode, int newSize){
MList *newList;
newList = *ml;
bucketNode *tempNode = insertNode;
tempNode->next = NULL;
unsigned long currentHash = me_hash((tempNode->nestedEntry), newSize);
if((newList->currentTable[currentHash].bucketSize) == 0) {
newList->currentTable[currentHash].first = tempNode;
newList->currentTable[currentHash].bucketSize = (newList->currentTable[currentHash].bucketSize) + 1;
}
else{
bucketNode *cursorNode;
cursorNode = newList->currentTable[currentHash].first;
while((cursorNode->next) != NULL){
cursorNode = cursorNode->next;
}
cursorNode->next = tempNode;
newList->currentTable[currentHash].bucketSize = (newList->currentTable[currentHash].bucketSize) + 1;
}
}
【问题讨论】:
-
我才刚刚开始使用 C。我对它有一点了解,但不确定我将如何在这种情况下准确地应用它 :)
-
我没有看到错误.. 但作为旁注,如果您将新节点插入到列表的前面,则不必在列表的末尾插入它们这是一个 O(1) 操作而不是 O(n) 操作,并且需要更少的代码:)
-
你能断言
me_hash()函数将始终返回一个介于 0 和 newSize -1 之间的值吗? -
与段错误问题无关,但在您当前的
ml_add()实现中存在内存泄漏。请注意hashtable需要调整大小时的代码流程,首先调整hashtable的大小,然后递归调用ml_add()在调整大小的Hashtable上插入新节点;但是您不要在 tempNode 上调用free()。递归调用将重新创建一个新的 tempNode,而原来的 tempNode 将丢失,从而造成内存泄漏。 -
我还认为您在
ml_resize()中泄漏了内存。当你释放oldList时,你应该先释放oldList->currentTable。我建议创建一个函数来封装 MList 实例的“破坏”以避免此类问题。
标签: c pointers hash segmentation-fault hashtable