【问题标题】:c- sysmalloc assertion problemsc- sysmalloc 断言问题
【发布时间】:2017-11-20 20:21:06
【问题描述】:

我希望有人可以帮助我了解我在哪里出错了。我正在实施一个程序来检查拼写正确性。在此过程中,我使用 trie 数据结构将字典文本文件加载到内存中以检查单词。

总体而言,它似乎按预期运行,但在加载尽可能长的单词时,我遇到了很多问题,即 pneumonoultramicroscopicsilicovolcanoconiosis。我不明白为什么,但首先让我介绍一些代码 -

/**
* Loads dictionary into memory. Returns true if successful else false.
*/
bool load(const char *dictionary)
{
    FILE *dict = fopen(dictionary, "r");
    if (dict == NULL)
    {
        fprintf(stderr, "Could not open %s dictionary file.\n", dictionary);
        return false;
    }

    // Initialise the root t_node
    root = (t_node *) malloc(sizeof(t_node));
    if (root == NULL)
    {
        fprintf(stderr, "Could not allocate memory to trie structure.\n");
        return false;
    }

    // Set all current values in root to NULL and is_word to false
    for (int i = 0; i < ALPHA_SIZE; i++)
    {
        root->branch[i] = NULL;
    }
    root->is_word = false;


    while (1)
    {
        // Create char aray to hold words from .txt dictionary file once read 
        char *word = (char *) malloc((LENGTH + 1) * sizeof(char));

        if (fscanf(dict, "%s", word) == EOF)
        {
            free(word);
            break;
        }

        t_node *cursor = root;
        int len = strlen(word) + 1;
        for (int i = 0; i < len; i++)
        {
            if (word[i] == '\0')
            {
                cursor->is_word = true;
                cursor = root;
                word_count++;
            }

            else
            {
                int index = (word[i] == '\'') ? ALPHA_SIZE - 1 : tolower(word[i]) - 'a';
                if (cursor->branch[index] == NULL)
                {
                    cursor->branch[index] = (t_node *) malloc(sizeof(t_node));
                    for (int j = 0; j < ALPHA_SIZE; j++)
                    {
                        cursor->branch[index]->branch[i] = NULL;
                    }
                    cursor->branch[index]->is_word = false;
                }
            cursor = cursor->branch[index];
            }
        }

        free(word);
    }

    fclose(dict);
    return true;
}

这是我将字典加载到内存中的全部功能。作为参考,我定义了 trie 结构并在此函数之前创建了根。 LENGTH 定义为 45 以说明可能的最长单词。 ALPHA_SIZE 为 27,包括小写字母和撇号。

正如我已经用所有其他较短的单词所说的那样,此功能运行良好。但是对于最长的单词,该函数会处理大约一半的单词,在遇到 sysmalloc 断言问题之前到达单词变量的索引 29,然后中止。

我试图找出这里发生的事情,但我能看到的最多的是它在 -

cursor->branch[index] = (t_node *) malloc(sizeof(t_node));

一旦它到达单词的第 29 个索引,但之前没有其他索引。我能找到的所有其他帖子都与给出此错误的函数有关,这些函数根本不起作用,而不是大多数时候出现异常。

谁能看到我看不到的内容以及我在这段代码中犯的错误?感谢您提供任何帮助,并感谢大家花时间考虑我的问题。

* 更新 *

首先,我要感谢大家的帮助。看到有多少人回复我的问题以及他们回复的速度有多快,我感到非常惊喜!我无法对你们所有人的帮助表示感谢。尤其是 Basile Starynkevitch,他为我提供了大量信息并提供了很多帮助。

我非常尴尬地说我发现了我的问题,而且在转向 SO 之前我应该​​很长时间才发现它。所以我必须为把大家的时间浪费在这么愚蠢的事情上而道歉。我的问题就在这里-

else
{
    int index = (word[i] == '\'') ? ALPHA_SIZE - 1 : tolower(word[i]) - 'a';
    if (cursor->branch[index] == NULL)
    {
        cursor->branch[index] = (t_node *) malloc(sizeof(t_node));
        for (int j = 0; j < ALPHA_SIZE; j++)
        {
            cursor->branch[index]->branch[j] = NULL; // <<< PROBLEM WAS HERE
        }
        cursor->branch[index]->is_word = false;
    }
    cursor = cursor->branch[index];
}

在我的代码中,最初我有 'cursor->branch[index]->branch[i] = NULL' 我在那个循环中迭代了 'int j',而不是 i ....

Sooooo 再次感谢大家的帮助!对于我的问题格式不正确,我深表歉意,今后我会更好地遵守 SO 准则。

【问题讨论】:

  • 这里不足以重现问题。请使用minimal reproducible example 更新您的问题。
  • 不要将 malloc 的结果投射到 c 中。
  • 在 valgrind 下运行(如果你在 linux 上)
  • 顺便说一句,它是malloc,而不是sysmalloc
  • 如何断言len &lt;= LENGTH

标签: c trie


【解决方案1】:

你的

  char *word = (char *) malloc((LENGTH + 1) * sizeof(char));

后面没有测试malloc的失败;您需要添加:

  if (!word) { perror("malloc word"); exit(EXIT_FAILURE); }

之前

          if (fscanf(dict, "%s", word) == EOF)

因为在NULL 指针上使用fscanf%s 是错误的(可能是undefined behavior)。

顺便说一句,最新版本的fscanf(或dynamic memory TR)在读取字符串时接受%ms 说明符以分配一个字符串。在这些系统上,您可以:

 char*word = NULL;
 if (fscanf(dict, "%ms", &word) == EOF))
   break;

有些系统有getline,见this

最后,使用所有警告和调试信息进行编译(gcc -Wall -Wextra -g 使用 GCC),改进您的代码以不出现警告,并使用调试器 gdbvalgrind

BTW pneumonoultramicroscopicsilicovolcanoconiosis 有 45 个字母。你需要一个额外的字节来终止 NUL(否则你有一个buffer overflow)。所以你的LENGTH 至少应该是 46(我建议选择稍微大一点的,也许是 64;事实上我建议使用 systematically C dynamic memory allocation 并避免硬编码这样的限制和代码robust style,跟在GNU coding standards之后)。

【讨论】:

  • 嗯...谢谢你的帮助巴西尔。我已经实施了您的建议,但问题仍然存在。该函数成功地将我最长的单词加载到单词中,并开始根据我的 trie 检查每个索引。在故障发生之前,它只是通过这个词的一部分。如果我取出那个单词并加载到同一个字典中,问题就消失了。
  • 我不确定我是否理解你的最后一部分。单词是 45,LENGTH 是 45,malloc 使用 LENGTH+1 - 为什么这还不够?
  • 所以你有一个可重现的错误。现在是学习如何使用调试器的时候了。花几个小时阅读gdb 的文档并进行实验
  • 感谢您的所有帮助。我非常感谢您为此付出的所有时间和精力。我发现了我的问题并在上面报告了它。
猜你喜欢
  • 1970-01-01
  • 2021-02-17
  • 2021-08-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多