c- sysmalloc 断言问题
c- sysmalloc assertion problems
我希望有人能帮助我理解我哪里出了问题。我正在实施一个检查拼写正确性的程序。在此过程中,我使用 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] == '[=10=]')
{
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 结构并在此函数之前创建了 root。 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',而不是我 ....
再次感谢大家的帮助!很抱歉我的问题格式不正确,以后我会更好地遵守 SO 指南。
你的
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
(or with dynamic memory TR) 的最新版本接受 %ms
说明符,以便在读取字符串时 分配 字符串。在这些系统上,您可以:
char*word = NULL;
if (fscanf(dict, "%ms", &word) == EOF))
break;
有些系统有 getline
, see this.
最后,使用所有警告和调试信息进行编译(使用 GCC gcc -Wall -Wextra -g
),改进代码以消除警告,并使用调试器 gdb
和 valgrind。
顺便说一句 pneumonoultramicroscopicsilicovolcanoconiosis 有 45 个字母。终止 NUL 需要一个额外的字节(否则你有一个 buffer overflow). So your LENGTH
should be at least 46 (and I recommend choosing something slightly bigger, perhaps 64; in fact I recommend using systematically C dynamic memory allocation and avoiding hard-coding such limits and code in a more robust style, following the GNU coding standards)。
我希望有人能帮助我理解我哪里出了问题。我正在实施一个检查拼写正确性的程序。在此过程中,我使用 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] == '[=10=]')
{
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 结构并在此函数之前创建了 root。 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',而不是我 ....
再次感谢大家的帮助!很抱歉我的问题格式不正确,以后我会更好地遵守 SO 指南。
你的
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
(or with dynamic memory TR) 的最新版本接受 %ms
说明符,以便在读取字符串时 分配 字符串。在这些系统上,您可以:
char*word = NULL;
if (fscanf(dict, "%ms", &word) == EOF))
break;
有些系统有 getline
, see this.
最后,使用所有警告和调试信息进行编译(使用 GCC gcc -Wall -Wextra -g
),改进代码以消除警告,并使用调试器 gdb
和 valgrind。
顺便说一句 pneumonoultramicroscopicsilicovolcanoconiosis 有 45 个字母。终止 NUL 需要一个额外的字节(否则你有一个 buffer overflow). So your LENGTH
should be at least 46 (and I recommend choosing something slightly bigger, perhaps 64; in fact I recommend using systematically C dynamic memory allocation and avoiding hard-coding such limits and code in a more robust style, following the GNU coding standards)。