繁体   English   中英

此TRIE算法代码在CS50 IDE编译器上运行,但是在Windows的TDM-GCC中进入无限循环

[英]This TRIE algorithm code runs on CS50 IDE compiler but goes into an infinite loop in TDM-GCC on Windows

编写此代码是为了使用TRIE数据结构在字典中搜索单词。 这段代码可以在我的CS50 IDE编译器上同时使用make(Clang)和GCC完美运行,并且始终能给出正确的答案,但是当我在GCC编译器(TDM-GCC)上运行相同的代码时,它将陷入无限循环。 它开始使用大量RAM(直到我强行关闭它之前,才占用512 MB)。 在两种情况下,我运行的代码完全相同。 同样在两种情况下,代码都能完美编译。

#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;
}

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

由于以下问题,您的代码难以调试和维护:

  1. 重复-这容易出错,请改用函数
  2. 过多的不必要的类型转换-检查C类型系统以及类型如何隐式转换为彼此
  3. 奇怪的typedefs-不要重新定义指针类型,除非您使用某种后缀或前缀来表示相应的typedef确实是指针
  4. 括号太多,则不需要最多的括号(尤其是那种东西(* 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;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM