初始化哈希表的问题
尝试使用链表实现哈希表来解决冲突问题,我在初始化哈希表的代码中遇到了一些问题。 我遇到分段错误。为了找出问题到底出在哪里,我使用了 valgrind。使用这个工具我收到警告:
“地址 0x8 未堆栈、未分配 或(最近)被释放”
几乎每次我尝试“编辑”哈希表。 例如,大小、插入、删除等。 我一遍又一遍地查看我的代码,但我找不到问题所在。我以为我已经正确地分配和堆叠了所有内容。但有了这个消息,显然出了问题。 对此有什么想法吗?
我的代码:
//hash table structure
typedef struct HashTable
{
int size; //size of table with connections
struct List **table; //table elements
}HashTable;
typedef struct List
{
char* number;
struct List *next;
}List;
struct HashTable *initHashTable(int size)
{
struct HashTable *blankTable=(struct HashTable *)malloc(sizeof(struct HashTable));
if (size<1)
{
return NULL;
}
if ((blankTable=malloc(sizeof(HashTable)))==NULL)
{
return NULL;
}
if ( (blankTable->table=malloc(size*sizeof(List))) == NULL)
{
return NULL;
}
int i;
for (i=0; i<size; i++) //initializes hash table
{
blankTable->table[i]=malloc(sizeof(List));
blankTable->table[i]=NULL; //Valgrind :: Invalid write of size 8
}
blankTable->size = size;
//printf("blankTable size:%d\n",blankTable->size);
return blankTable;
}
更多注释: 使用以下代码来搜索哈希表中是否已存在某个数字。我从 valgrind 得到这个:
大小 8 的读取无效 ==3773==在0x40110E:查找(360) ==3773== 地址 0x8 未被堆栈、分配或(最近)释放
struct List *lookup(HashTable *hashtable,char *number)
{
struct List *list= (struct List *) malloc (sizeof(struct List )); ;
unsigned int hashval= hash(number);
if ( (hashtable->table[hashval])!=NULL)
{
for( list=hashtable->table[hashval]; list!=NULL; list=list->next)
{ if(strcmp(number,list->number)==0) //SEGMENTATION!
{
return list;
}
}
}
return NULL;
}
事实上,如果我调用查看表的大小,我也会得到一个分段,这让我更担心。 调用此:
unsigned int size = Array[pos].TableHead->size;
Array[pos].TableHead 是指向 hashTable 结构的指针。
编辑:
运行 valgring 我得到这个报告:
Invalid write of size 8
==8724== at 0x4016D2: initHashTable (hash.c:524)
==8724== by 0x4019CE: main (hash.c:792)
==8724== Address 0x5199180 is 8 bytes after a block of size 8 alloc'd
==8724== at 0x4C25153: malloc (vg_replace_malloc.c:195)
==8724== by 0x4016B6: initHashTable (hash.c:522)
==8724== by 0x4019CE: main (hash.c:792)
==8724== Use of uninitialised value of size 8
==8724== at 0x4C264C4: strcmp (mc_replace_strmem.c:412)
==8724== by 0x4017A0: lookup (hash.c:551)
==8724== by 0x401820: add(hash.c:566)
==8724== by 0x401AAB: main (hash.c:817)
==8724==
==8724== Invalid read of size 1
==8724== at 0x4C264C4: strcmp (mc_replace_strmem.c:412)
==8724== by 0x4017A0: lookup (hash.c:551)
==8724== by 0x401820: add (hash.c:566)
==8724== by 0x401AAB: main (hash.c:817)
==8724== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==8724==
==8724==
==8724== Process terminating with default action of signal 11 (SIGSEGV)
==8724== Access not within mapped region at address 0x0
==8724== at 0x4C264C4: strcmp (mc_replace_strmem.c:412)
==8724== by 0x4017A0: lookup (hash.c:551)
==8724== by 0x401820: add (hash.c:566)
==8724== by 0x401AAB: main (hash.c:817)
==8724== If you believe this happened as a result of a stack
==8724== overflow in your program's main thread (unlikely but
==8724== possible), you can try to increase the size of the
==8724== main thread stack using the --main-stacksize= flag.
==8724== The main thread stack size used in this run was 8388608.
读到这个我的第一个想法是我的号码没有空终止符。 因此,我重新初始化它,并在其最后一个索引上添加了 null。不幸的是,如您所见,问题仍然存在。在第一次运行时(查找函数),它将该数字与列表中的数字进行比较,该数字为空。有细分。但我想知道为什么。不能直接返回NULL吗?
谢谢。
Trying to implement a hash table using linked lists to solve collision's problem I'm facing some problems with my code for initializing the hash table.
I get a segmentation fault. Trying to see where exactly the problem is I used the valgrind. With this tool i get the warning:
"Address 0x8 is not stack'd, malloc'd
or (recently) free'd"
on almost every my try to 'edit' the hash table.
eg for the size,to insert sth,to delete etc.
I've looked again and again my code but I cant find what's wrong. I thought I had malloc'd and stack'd everything correctly. But with this message,clearly sth goes wrong.
Any ideas on this?
My code:
//hash table structure
typedef struct HashTable
{
int size; //size of table with connections
struct List **table; //table elements
}HashTable;
typedef struct List
{
char* number;
struct List *next;
}List;
struct HashTable *initHashTable(int size)
{
struct HashTable *blankTable=(struct HashTable *)malloc(sizeof(struct HashTable));
if (size<1)
{
return NULL;
}
if ((blankTable=malloc(sizeof(HashTable)))==NULL)
{
return NULL;
}
if ( (blankTable->table=malloc(size*sizeof(List))) == NULL)
{
return NULL;
}
int i;
for (i=0; i<size; i++) //initializes hash table
{
blankTable->table[i]=malloc(sizeof(List));
blankTable->table[i]=NULL; //Valgrind :: Invalid write of size 8
}
blankTable->size = size;
//printf("blankTable size:%d\n",blankTable->size);
return blankTable;
}
MORE NOTES:
Using the following code to search if a number already exists or not in the hash table. I get from valgrind this:
Invalid read of size 8
==3773== at 0x40110E: lookup(360)
==3773== Address 0x8 is not stack'd, malloc'd or (recently) free'd
struct List *lookup(HashTable *hashtable,char *number)
{
struct List *list= (struct List *) malloc (sizeof(struct List )); ;
unsigned int hashval= hash(number);
if ( (hashtable->table[hashval])!=NULL)
{
for( list=hashtable->table[hashval]; list!=NULL; list=list->next)
{ if(strcmp(number,list->number)==0) //SEGMENTATION!
{
return list;
}
}
}
return NULL;
}
The fact that i get also a segmentation if i call to see the table's size it's sth that worries me even more.
Calling this:
unsigned int size = Array[pos].TableHead->size;
Array[pos].TableHead is a pointer to the struct of the hashTable.
EDIT:
Running the valgring I get this report:
Invalid write of size 8
==8724== at 0x4016D2: initHashTable (hash.c:524)
==8724== by 0x4019CE: main (hash.c:792)
==8724== Address 0x5199180 is 8 bytes after a block of size 8 alloc'd
==8724== at 0x4C25153: malloc (vg_replace_malloc.c:195)
==8724== by 0x4016B6: initHashTable (hash.c:522)
==8724== by 0x4019CE: main (hash.c:792)
==8724== Use of uninitialised value of size 8
==8724== at 0x4C264C4: strcmp (mc_replace_strmem.c:412)
==8724== by 0x4017A0: lookup (hash.c:551)
==8724== by 0x401820: add(hash.c:566)
==8724== by 0x401AAB: main (hash.c:817)
==8724==
==8724== Invalid read of size 1
==8724== at 0x4C264C4: strcmp (mc_replace_strmem.c:412)
==8724== by 0x4017A0: lookup (hash.c:551)
==8724== by 0x401820: add (hash.c:566)
==8724== by 0x401AAB: main (hash.c:817)
==8724== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==8724==
==8724==
==8724== Process terminating with default action of signal 11 (SIGSEGV)
==8724== Access not within mapped region at address 0x0
==8724== at 0x4C264C4: strcmp (mc_replace_strmem.c:412)
==8724== by 0x4017A0: lookup (hash.c:551)
==8724== by 0x401820: add (hash.c:566)
==8724== by 0x401AAB: main (hash.c:817)
==8724== If you believe this happened as a result of a stack
==8724== overflow in your program's main thread (unlikely but
==8724== possible), you can try to increase the size of the
==8724== main thread stack using the --main-stacksize= flag.
==8724== The main thread stack size used in this run was 8388608.
Reading this my first thought that my number didnt have a null terminator.
So,i re-initialize it and on its last index i added the null. Unfortunately,problem as you can see remains. On its first run (the lookup function) it compares the number with the list;s number which is null. There is the segmentation. But im wandering why. Can't it just return NULL ?
Thank you.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您为列表项分配内存,然后将其设置为
NULL
(0x0)。You allocate memory for List item and then set it to
NULL
(0x0).以下玩具程序可以使用您发布的结构定义和函数正常工作(至少不会出现段错误):
我假设上述内容是正确的,您认为 NULL 指针是“空”清单,对吗? (因此,
insert
函数会将适当的 NULL 替换为新列表的第一个元素。)如果是这样,您可以大大简化事情。可以编写一个初始化程序,使上述玩具程序通过 valgrind 干净地运行。我不想欺骗您的发现,但我可以暗示您可能想了解一下什么是灵活数组以及它们是如何工作的。
忽略初始化函数中的问题(一旦应用程序没有出现段错误,valgrind 应该非常准确地告诉您出了什么问题),查找函数中函数
hash()
的界限是什么?您尝试读取
hashtable->table[hash(number)]
的值,因此hashtable
必须至少使用那么多元素进行初始化,否则您将读取您尚未分配的内存(因此出现分段错误)。也许您的意思是
更新:您无法从您发布的 valgrind 日志中将空指针传递给
strcmp
,这就是您出现分段错误的原因。上面的查找函数已更新为更多断言,以确保不会发生这种情况。另外,valgrind 提示您已将未初始化的值传递给 strcmp,这可能是空指针(如果未初始化的值恰好为零)。但是,仍然缺少一些重要信息来正确回答这个问题,您可以将整个文件
hash.c
发布到某个地方吗?通读该文件后:我必须说实话,您在该代码中遇到了一些非常严重的问题:-)我认为您尚未掌握手动内存处理和初始化的概念 - 您是否可能先学习了 Java ?
无论如何,以下是我发现的问题(排名不分先后):
init_array_for_antennas()
中,您初始化本地变量 MyArray,而不是全局 >。只需删除局部变量就可以了。malloc()
“初始化”指针,然后将指针设置为其实际值。这是典型的内存泄漏;您将无法释放此类内存,因为您覆盖了对它的引用。number[strlen(number)]='\0';
是多余的。想想 strlen() 是如何工作的,你应该自己看看。assert(pointer_you_dereference_later != NULL);
是错误的。bucket_size
,在其他地方使用哈希表结构字段size
。这是一个即将发生的错误,要么使大小字段成为实际的编译时常量,要么正确使用运行时值。calloc()
而不是malloc()
,您将获得归零的内存。例如,使用 calloc() 分配指针数组将使它们初始化为 NULL,并且您不需要显式地执行此操作。好吧,可能还有更多,但今晚就这样了。我猜列表中的第一点是您实际问题的原因:-)
The following toy program works correctly (well, does not segfault at least) with the struct definitions and functions you posted:
I assume the above is correct, that you consider a NULL pointer to be an "empty" list, right? (The
insert
function would thus replace the appropriate NULL with the first element of a new list.)If so, you can simplify things a great deal. It is possible to write an initializer that makes the above toy program run cleanly through valgrind. I don't want to cheat you of the discovery, but I can hint that you might want to look up what flexible arrays are and how they work.
Ignoring the problems in the initialization function (valgrind should tell you pretty precisely what is wrong once you have the application not segfaulting), what are the bounds for the function
hash()
in the lookup function?You try to read the value of
hashtable->table[hash(number)]
, sohashtable
must be initialized with at least that many elements, otherwise you will read from memory you have not allocated (hence the segmentation fault).Perhaps you meant
Updates: You can not pass a null pointer to
strcmp
, from the valgrind log you posted that is the reason you get a segmentation fault. The lookup function above has been updated with some more asserts to make sure that this does not happen.Also, the valgrind hints that you have passed an uninitialized value to
strcmp
, this might be the null pointer (if the uninitialized value happens to be zeroed). However, there is still some vital information lacking to properly answer this question, could you perhaps post the whole filehash.c
somewhere?After reading through the file: I have to be honest, you have some very serious problems in that code :-) I think you do not yet grasp the concept of manual memory handling and initialization -- is it perhaps possible that you learned Java first?
In any case, here are the problems I spot in no particular order:
init_array_for_antennas()
, you initialize the local variable MyArray, not the global. Just remove the local variable and you should be OK.init_array_for_antennas()
is just redundant.malloc()
and then set the pointer to its actual value. This is a classic memory leak; you will not be able to free such memory since you overwrite the reference to it.number[strlen(number)]='\0';
is, well, just redundant. Think about how strlen() works and you should see it yourself.assert(pointer_you_dereference_later != NULL);
is just wrong.bucket_size
in some places, and the hashtable struct fieldsize
in others. This is an error just waiting to happen, either make the size field an actual compile-time constant, or use the runtime value properly.calloc()
instead ofmalloc()
you get zeroed memory. For instance, allocating an array of pointers withcalloc()
will make them initialized to NULL, and you do not need to do that explicitly.Well, there's probably more but that's it for tonight. I'd guess the first point in the list is the cause of your actual problem :-)