2010-02-02 109 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;