初始化哈希表的问题

时间:2010-11-27 17:33:08

标签: c list hashtable segmentation-fault chaining

尝试使用链接列表实现哈希表来解决冲突问题我的代码初始化哈希表时遇到了一些问题。 我遇到了分段错误。试着看看问题究竟在哪里我使用了valgrind。使用此工具,我收到警告:

  

“地址0x8未堆叠,malloc'd   或(最近)免费“

几乎每次尝试'编辑'哈希表。 例如尺寸插入 ......,删除等 我一遍又一遍地看着我的代码,但我找不到什么是错的。我以为我有malloc'd并正确堆叠所有内容。但是有了这个消息,显然是错的。 关于这个的任何想法?

我的代码:

     //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没有堆叠,malloc'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;
}

如果我打电话来查看表的大小,我也会得到一个分段,这让我更加担心。 打电话给:

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 。不幸的是,你看到的问题仍然存在。在第一次运行(查找函数)时,它将数字与列表进行比较; s数字为空。有分割。但我徘徊为什么。它不能只返回NULL吗?

谢谢。

2 个答案:

答案 0 :(得分:5)

blankTable->table[i]=malloc(sizeof(List));
blankTable->table[i]=NULL;

您为List项目分配内存,然后将其设置为NULL(0x0)。

答案 1 :(得分:2)

以下玩具程序使用您发布的结构定义和函数正常工作(好吧,至少不会发生段错误):

#include <stdlib.h>
#include <assert.h>

/* code from question omitted */

int main(void) 
{
    HashTable * hash = initHashTable(5);
    int i;

    assert(hash->size == 5);

    for ( i = 0; i < hash->size; i++ )
        assert(hash->table[i] == NULL);

    free(hash);

    return EXIT_SUCCESS;
}

我假设上面的说法是正确的,你认为NULL指针是一个“空”列表,对吧? (因此insert函数将用新列表的第一个元素替换相应的NULL。)

如果是这样,你可以大大简化事情。可以编写一个初始化程序,使上述玩具程序通过valgrind干净地运行。我不想欺骗你的发现,但我可以暗示你可能想要查找灵活的数组是什么以及它们是如何工作的。

忽略初始化函数中的问题(一旦你的应用程序没有segfaulting,valgrind应该告诉你非常准确的错误),查找函数中函数hash()的界限是什么?

您尝试读取hashtable->table[hash(number)]的值,因此必须使用至少那么多元素初始化hashtable,否则您将从尚未分配的内存中读取(因此会出现分段错误)。< / p>

也许你的意思是

List * lookup(HashTable *hashtable, char *number)
{
    assert(hashtable != NULL);
    assert(number != NULL);

    unsigned int hashval = hash(number) % hashtable->size;
    List * list = hashtable->table[hashval];

    assert( list == NULL || list->number != NULL );

    while ( list != NULL && strcmp(number,list->number)!=0)
    {
        list = list->next;
        assert ( list == NULL || list->number != NULL );
    }

    return list;
}

更新:您无法从您发布的valgrind日志中将空指针传递给strcmp,这是导致分段错误的原因。上面的查找函数已经更新了一些断言,以确保不会发生这种情况。

此外,valgrind暗示您已将未初始化的值传递给strcmp,这可能是空指针(如果未初始化的值恰好为零)。但是,仍有一些重要信息无法正确回答这个问题,您是否可以在某处发布整个文件hash.c

阅读完文件后:说实话,你在代码中遇到了一些非常严重的问题:-)我认为你还没有掌握手动内存处理和初始化的概念 - 是否有可能你学习Java第一?

无论如何,我发现的问题没有特别的顺序:

  1. init_array_for_antennas()中,您初始化本地变量MyArray,而不是全局。只需删除局部变量就可以了。
  2. 静态和全局变量被隐式初始化为零,因此init_array_for_antennas()中的几乎所有内容都是多余的。
  3. 在几个地方,您使用malloc()“初始化”指针,然后将指针设置为其实际值。这是经典的内存泄漏;因为你覆盖对它的引用,你将无法释放这些内存。
  4. 陈述number[strlen(number)]='\0';是多余的。想一想strlen()是如何工作的,你应该自己看看。
  5. 如果您还没有,请阅读断言,并了解如何使用它们来检查您的假设。评论assert(pointer_you_dereference_later != NULL);是错误的。
  6. 当你已经有一个指向字符串的指针时,你不必将内容复制到本地数组,然后将该数组传递给底层函数 - 只需传递指针!
  7. 您在某些地方使用全局常量bucket_size,在其他地方使用哈希表结构域size。这是一个等待发生的错误,要么使size字段成为实际的编译时常量,要么正确使用运行时值。
  8. 关于风格问题,实际上,你可以将很多结构体类型化为漂亮的人类可读名称,但无论如何都会添加“struct”关键字。
  9. 如果您使用calloc()而不是malloc(),则会获得归零内存。例如,使用calloc()分配指针数组会使它们初始化为NULL,而您无需明确地执行此操作。
  10. 嗯,可能会有更多,但今晚就是这样。我猜这个列表中的第一点是你实际问题的原因: - )