2017-06-23 51 views
0

編寫此代碼以使用TRIE數據結構在字典中搜索單詞。這段代碼在使用make(Clang)和GCC的CS50 IDE編譯器上完美運行,並始終給出正確的答案,但是當我在GCC編譯器(TDM-GCC)上運行相同的代碼時,它會進入無限循環。它開始使用大量的RAM(512 MB直到我強制關閉它)。我所運行的代碼在兩種情況下都完全相同。同樣在這兩種情況下,代碼完美編譯。此TRIE算法代碼運行在CS50 IDE編譯器上,但在Windows上的TDM-GCC中進入無限循環

#include <stdio.h> 
#include <string.h> 
#include <ctype.h> 
#include <stdlib.h> 

struct trieblock123; 
typedef struct trieblock123 trieblock; 
typedef trieblock *node; 
struct trieblock123 
{ 
    char alphabet; 
    char reply[5]; 
    node pnt; 
}; 


typedef struct 
{ 
    node first; 
    int count; 
}head; 

void load(FILE* dict, head* header); 
void init(node pointer); 

int main(void) 
{ 
    FILE* dict = fopen("large", "r"); 

    head* header = malloc(sizeof(head)); 
    (*header).count = 0; 
    (*header).first = NULL; 


    node curtrie = NULL; 
    node temptrie = NULL; 
    node temptrie1 = NULL; 
    char temp; 
    temp = fgetc(dict); 
    int counter = 0; 
    temptrie = (node)(malloc(26 * sizeof(trieblock))); 
    int i; 
    for(i = 0; i < 26; i++) 
    { 
     (temptrie[i]).alphabet = (char)(((int)('a')) + i); 
     (temptrie[i]).pnt = NULL; 
    } 
    if(counter == 0) 
    { 
     (*header).first = temptrie; 
    } 
    while(((int)(temp) <= (int)('z') && (int)(temp) >= (int)('a')) || temp == '\n') 
    { 
     if(((int)(temp) > (int)('z') || (int)(temp) < (int)('a')) && temp != '\n') 
      break; 
     curtrie = temptrie; 

     while(temp != '\n') 
     { 
      char temp1; 
      temp1 = fgetc(dict); 
      if((curtrie[(int)(temp) - (int)('a')]).pnt == NULL) 
      { 
       if(temp1 != '\n') 
       { 
        temptrie1 = (node)(malloc(26 * sizeof(trieblock))); 
        for(i = 0; i < 26; i++) 
        { 
         (temptrie1[i]).alphabet = (char)(((int)('a')) + i); 
         (temptrie1[i]).pnt = NULL; 
        } 

        (curtrie[(int)(temp) - (int)('a')]).pnt = temptrie1; 
        curtrie = temptrie1; 
       } 
       else 
       { 
        strcpy((curtrie[(int)(temp) - (int)('a')]).reply, "yes"); 
       } 
      } 
      else if((curtrie[(int)(temp) - (int)('a')]).pnt != NULL) 
      { 
       curtrie = (curtrie[(int)(temp) - (int)('a')]).pnt; 
      } 
      fseek(dict, -1 * sizeof(char), SEEK_CUR); 
      temp = fgetc(dict); 
     } 


     if(temp == '\n') 
     { 
      temp = fgetc(dict); 
     } 

     counter++; 
    } 
    (*header).count = counter; 

    char tocheck[100]; 
    scanf("%s", tocheck); 

    i = 0; 
    node start = NULL; 
    start = temptrie; 

    for(i = 0; i < strlen(tocheck); i++) 
    { 
     char cha = tocheck[i]; 
     if(i != strlen(tocheck) - 1) 
     { 
      if((start[(int)(cha) - (int)('a')]).pnt == NULL) 
      { 
       printf("mis-spelled\n"); 
       break; 
      } 
      else 
      { 
       start = (start[(int)(cha) - (int)('a')]).pnt; 
      } 
     } 
     else 
     { 
      if(strcmp(((start[(int)(cha) - (int)('a')]).reply), "yes") == 0) 
      { 
       printf("correctly spelled\n"); 
       break; 
      } 
      else 
      { 
       printf("mis-spelled\n"); 
       break; 
      } 
     } 
    } 
    return 0; 
} 
+0

所以通過代碼在調試器,並找出什麼不正常。它編譯並不意味着它是正確的。 –

+3

(副詞)爲什麼(動詞)是(名詞)一切(動詞)鑄造? – ThingyWotsit

+0

沒有分析,while語句中的複合表達式看起來很可疑,僅僅是因爲它們的複雜性。 – ThingyWotsit

回答

0

但是,這可能不是您所期望的答案。

你的代碼難以調試和因爲這個問題保持:

  1. 重複 - 這是容易出錯,使用的功能,而不是
  2. 太多不必要的強制類型轉換 - 檢查的C類型系統和類型如何隱含互相轉換
  3. 奇怪的typedefs - 除非使用某種後綴或前綴來指示相應的typedef確實是指針,否則不要重新定義指針類型
  4. 太多括號,您不需要大多數括號(ES pecially那種東西(* S).A =什麼用途 - >代替)

其他一些問題是:

  1. 每當你malloc的不只是期望在那裏零(事實上不要期望在任何時候獲得任何內存),如果回覆初始化爲垃圾,則原始代碼可能會出現段錯誤。
  2. C中的字符串是零終止的,因此strlen會涉及遍歷整個字符串,除非您正在修改它,只是將結果緩存在變量中並使用它。
  3. 跟蹤您的條件語句,不需要再次檢查負面條件。
  4. 使用IO嘗試在適當的時候儘量減少調用。
  5. 不要混合責任。例如,檢查你的特定結構中字符串存在的代碼應該不是負責打印答案的人。
  6. 不要使用字符串作爲標誌,這只是很容易混淆。

這應該是等同的(除非我搞砸了):

#include <stdio.h> 
#include <string.h> 
#include <ctype.h> 
#include <stdlib.h> 

typedef struct node_s node_t; 
struct node_s { 
    char alphabet; 
    char present; 
    node_t *pnt; 
}; 

typedef struct { 
    node_t *first; 
    int count; 
} head_t; 

#define NLETTERS 26 
inline static int is_letter(char c) { return c <= 'z' && c >= 'a'; } 

inline static node_t* new_trieblock() { 
    const int size = NLETTERS * sizeof(node_t); 
    node_t* block = malloc(size); 
    memset(block, 0, size); 
    for (int i = 0; i < NLETTERS; i++) { 
    block[i].alphabet = 'a' + i; 
    } 
    return block; 
} 

inline static int trie_has(node_t *n, char *str) { 
    node_t *trie = n; 
    int len = strlen(str); 
    for (int i = 0; i < len - 1; i++) { 
    trie = trie[str[i] - 'a'].pnt; 
    if (!trie) return 0;  
    } 
    return trie[str[len-1] - 'a'].present; 
} 

int main(void) { 
    FILE* dict = fopen("large", "r"); 

    head_t *header = malloc(sizeof(head_t)); 
    header->count = 0; 
    header->first = new_trieblock(); 

    node_t *trie = header->first; 
    char c = fgetc(dict); 
    int nc; 
    while(is_letter(c) || c == '\n') { 
     nc = fgetc(dict); 

     if (nc == '\n' || nc == EOF) { 
      trie[c - 'a'].present = 1; 
      header->count++; 
     } else { 
      if (!trie[c - 'a'].pnt) { 
      trie = trie[c - 'a'].pnt = new_trieblock(); 
      } else { 
      trie = trie[c - 'a'].pnt; 
      } 
     } 

     c = nc; 
     while (c == '\n') { 
      trie = header->first; 
      c = fgetc(dict); 
     } 
    } 

    char tocheck[100]; 
    scanf("%s", tocheck); 

    if (trie_has(header->first, tocheck)) { 
     printf("correctly spelled\n"); 
    } else { 
     printf("mis-spelled\n"); 
    } 

    return 0; 
} 
+0

感謝您的幫助我的代碼運行完美,但是我仍然無法弄清楚我的代碼中的錯誤,您可以給我一些鏈接來學習GCC中的調試? – Salmaan

+0

@Salmaan看看GDB手冊。不過,我主張僅將它作爲最後的手段使用,請記住,越早發現錯誤越便宜。使用幾個編譯器(比如說clang,gcc),使用嚴格的標誌(-Wall -Wextra -pedantic -Werror -pedantic-errors)。使用[memorysanitizer](https://clang.llvm.org/docs/MemorySanitizer.html)和朋友。 Valgrind也是一個非常強大的工具。雖然比使用工具更重要的是總是問自己,你剛寫的代碼是否足夠清晰,如果不是毫不猶豫地從頭開始重寫。希望這可以幫助你開始。 – tgregory

相關問題