2010-02-02 110 views
2

我在过去的48个小时左右一直在削减我的牙齿,试图在C中实现这个哈希表函数。我的代码很长(我意识到它不是最高效的,有些更多我和C一起玩,感受它是如何工作的等等)。C学习指针

我遇到的问题是我的主程序底部的最后一行(打印MyEntry-> Name)。我收到一个巴士错误,我不确定为什么。我不相信我应该在这个指针的主驱动程序中分配内存,但我可能是错的。

对不起,此代码的长度。 BTW SymEntry是“结构SymEntry {字符*名称,void *的属性,结构SymEntry *下一步}

#include <strings.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <ctype.h> 
#include <stdbool.h> 
#include "SymTab.h" 



struct SymTab * CreateSymTab(int Size) 
{ 
    struct SymTab *symtable; 
    if(!(symtable=malloc(sizeof(struct SymTab)))) return NULL; 
    if(!(symtable->Contents=calloc(Size, sizeof(struct SymEntry*)))) { 
      free(symtable); 
      return NULL; 
    } 

    symtable->Size=Size; 
    return symtable; 
} 

/* hash form hash value for string s, taken from 'The C Programming Language'*/ 
unsigned hash(struct SymTab *ATable, const char *s) 
{ 
    unsigned hashval, size; 
    size = ATable->Size;; 
    for (hashval = 0; *s != '\0'; s++) 
     hashval = *s + 31 * hashval; 
    return hashval % size; 
} 

bool EnterName(struct SymTab *ATable, 
      const char *Name, 
      struct SymEntry **AnEntry) 
{ 
      struct SymEntry *ptr; 
      unsigned hashvalue; 
      char *string; 
      struct SymEntry *previous; 

      string = malloc(strlen(Name)+1); 
      AnEntry=(struct SymEntry**)malloc(sizeof(struct SymEntry*)); 

      strcpy(string, Name); 
      printf("string is: is %s\n",string); 
      hashvalue = hash(ATable, string); 

      printf("hv is %d\n",hashvalue); 
      ptr = ATable->Contents[hashvalue]; 
      previous = NULL; 

      while(ptr) 
      { 
       printf("WHILE LOOP\n"); 
       if(!(strcmp(ptr->Name,string))) 
       { 
        printf("if(!strcmp(ptr->Name,string))\n"); 
        *AnEntry = ptr; 
        return true; 
       } 
       previous = ptr; 
       ptr=ptr->Next; 
      } 
      if(previous) 
      { 
       printf("IF (PREVIOUS)\n"); 
       if(!(ptr=malloc(sizeof(struct SymEntry)))) return false; 
       if(!(ptr->Name=string)) 
       { 
        printf("if(!(ptr->Name=string))\n"); 
        free(ptr); 
        return false; 
       } 
       ptr->Name = string; 
       previous->Next = ptr; 
       printf("Previous->Next: %s\n", previous->Next->Name); 
       *AnEntry = ptr; 
       return false; 
      } 
      else 
      { 
       printf("ELSE (PREVIOUS)\n"); 
       if(!(ptr=malloc(sizeof(struct SymEntry)))) return false; 
       if(!(ptr->Name=string)) 
       { 
        printf("if(!(ptr->Name=string))\n"); 
        free(ptr); 
        return false; 
       } 
       ptr->Name = string; 
       ATable->Contents[hashvalue] = ptr; 
       printf("here\n"); 
       *AnEntry = ptr; 
       printf("there\n"); 
       return false; 
      } 

} 

struct SymEntry * FindName(struct SymTab *ATable, const char *Name) 
{ 
    struct SymEntry *Entry; 
    unsigned hashvalue; 

    hashvalue = hash(ATable, Name); 
    Entry = ATable->Contents[hashvalue]; 

    while(Entry) 
    { 
       if(strcmp(Name,Entry->Name)==0) 
       { 
               return Entry; 
       } 
    } 
    return NULL; 
} 



main(int argc, char **argv) 
{ 
    struct SymTab *mysymtab; 
    struct SymEntry *myEntry; 

    mysymtab = CreateSymTab(1); 
    const char *string1 = "HELLO"; 
    printf("%d\n",6); 
    EnterName(mysymtab, string1, &myEntry); 
    printf("first: %s\n", mysymtab->Contents[0]->Name); 
    EnterName(mysymtab, string1, NULL); 
    EnterName(mysymtab, "WORLD", NULL); 
    printf("second: %s\n", mysymtab->Contents[0]->Name); 
    printf("second->Next: %s\n", mysymtab->Contents[0]->Next->Name); 
    EnterName(mysymtab, "[email protected]#$%", &myEntry); 
    printf("third: %s\n", mysymtab->Contents[0]->Name); 
    printf("third->Next: %s\n", mysymtab->Contents[0]->Next->Name); 
    printf("third->Next->Next: %s\n", mysymtab->Contents[0]->Next->Next->Name); 
    printf("myEntry->Name: %s\n", myEntry->Name); 
} 
+0

如果你是新的C,而不是使用调试器(我假设是所有printfs输出的原因),我建议服用时间来得心应手与一个,因为它会节省很多小时,并使许多好奇的虫子百分之一。无论如何,这是我的经验。 – 2010-02-02 22:51:15

回答

7

问题是这一行EnterName:

AnEntry=(struct SymEntry**)malloc(sizeof(struct SymEntry*)); 

你需要,只要你想删除AnEntry指向调用者指定的参数。

因为AnEntry可能为NULL,则还需要改变的每个实例:

*AnEntry = ptr; 

到:

if (AnEntry) 
    *AnEntry = ptr; 

正在发生的事情是,此功能时,AnEntry指向调用者想要改变的指针。当你改变AnEntry的值(即AnEntry = ...;)时,你的代码不会修改调用者希望你改变的指针,而是修改一些内部指针。因此,当EnterName返回时,myEntry仍然指向内存中的某个随机位置。

+0

谢谢你的工作。现在我觉得这很有道理。 再次感谢! – James 2010-02-02 22:50:41

+0

虽然在这个问题上,每个SymEntry的Next指针在所有情况下都应该设置为NULL,它不在'else'的情况下。 – 2010-02-02 22:51:57

+0

雅我也抓到了。此外,我现在修复的FindName函数中有一个无限循环...忘记了遍历列表。 – James 2010-02-02 23:03:06

0

当你在学习的时候,你的代码中有一些文体的WTF。例如,拿这部分。

if(!(ptr=malloc(sizeof(struct SymEntry)))) return false; 
if(!(ptr->Name=string)) 
{ 
    printf("if(!(ptr->Name=string))\n"); 
    free(ptr); 
    return false; 
} 
ptr->Name = string; 

它不一致。你为上面的AnEntry返回malloc,但不是这个malloc。要么做一个或另一个,但不要混合它。更好的是,用一种根本不“需要”演员的方式来写。

你不应该在if语句中赋值。尽管你仍然很清楚你想在malloc-case中做什么,但意图在字符串分配中被模糊处理。特别是因为它是多余的。当if评估为真时,ptr立即释放。当它评估为false时,再次完成完全相同的分配。此外,在这种情况下,它阻止了明显的优化。

下面是相同的代码重写:

if (string == NULL) 
{ 
    printf("string == NULL\n"); 
    return false; 
} 
ptr = malloc(sizeof *ptr); 
if (ptr == NULL) 
{ 
    return false; 
} 
ptr->Name = string;