在我因为没有看到过多的Valgrind问题而被撕裂之前:我做到了。我花了很长时间观察,而且我发现的所有人都没有/**
* Implements a dictionary's functionality.
*/
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dictionary.h"
// number of characters we are using (a-z and ')
#define LETTERS 27
// max guaranteed number of nonnegative char values that exist
#define CHARVALUES 128
// create node structure for trie
typedef struct node
{
struct node *children[LETTERS];
bool is_word;
}
node;
// create root node for trie
node *root;
// stores the size of our dictionary
unsigned int dict_size = 0;
/**
* Returns true if word is in dictionary else false.
*/
bool check(const char *word)
{
// keeps track of where we are; starts with root for each new word
node *current_node = root;
while (*word != '\0')
{
// indices: 'a' -> 0, ..., 'z' -> 25, '\' -> 26
int index = (tolower(*word) - 'a') % CHARVALUES;
if (index >= LETTERS - 1)
{
// by assumption, the char must be '\'' if not '\n' or a letter
index = LETTERS - 1;
}
// if the node we need to go to is NULL, the word is not here
if (current_node->children[index] == NULL)
{
return false;
}
// go to the next logical node, and look at the next letter of the word
current_node = current_node->children[index];
word++;
}
}
return current_node->is_word;
}
/**
* Loads dictionary into memory. Returns true if successful else false.
*/
bool load(const char *dictionary)
{
FILE *inptr = fopen(dictionary, "r");
if (inptr == NULL)
{
return false;
}
// allocate memory for the root node
root = malloc(sizeof(node));
// store first letter (by assumption, it must be a lowercase letter)
char letter = fgetc(inptr);
// stores indices corresponding to letters
int index = 0;
/**
* we can assume that there is at least one word; we will execute the loop
* and assign letter a new value at the end. at the end of each loop, due
* to the inside loop, letter will be a newline; we know the EOF in the
* dictionary follows a newline, so the loop will terminate appropriately
*/
do
{
// keeps track of where we are; starts with root for each new word
node *current_node = root;
// this loop will only execute if our character is a letter or '\''
while (letter != '\n')
{
// indices: 'a' -> 0, ..., 'z' -> 25, '\' -> 26
index = (letter - 'a') % CHARVALUES;
if (index >= LETTERS - 1)
{
// by assumption, the char must be '\'' if not '\n' or a letter
index = LETTERS - 1;
}
// allocate memory for a node if we have not done so already
if (current_node->children[index] == NULL)
{
current_node->children[index] = malloc(sizeof(node));
// if we cannot allocate the memory, unload and return false
if (current_node->children[index] == NULL)
{
unload();
return false;
}
}
// go to the appropriate node for the next letter in our word
current_node = current_node->children[index];
// get the next letter
letter = fgetc(inptr);
}
// after each linefeed, our current node represents a dictionary word
current_node->is_word = true;
dict_size++;
// get the next letter
letter = fgetc(inptr);
}
while (letter != EOF);
fclose(inptr);
// if we haven't returned false yet, then loading the trie must have worked
return true;
}
/**
* Returns number of words in dictionary if loaded else 0 if not yet loaded.
*/
unsigned int size(void)
{
return dict_size;
}
void clear(node *head)
{
for (int i = 0; i < LETTERS; i++)
{
if (head->children[i] != NULL)
{
clear(head->children[i]);
}
}
free(head);
}
/**
* Unloads dictionary from memory. Returns true if successful else false.
*/
bool unload(void)
{
clear(root);
return true;
}
正确的字节数。如果我不正确并且这是重复的,我将很乐意接受您的参考。
在这个程序中,我使用树来创建一个拼写检查器。我的代码中有很多东西需要修复,但内存泄漏是我真正需要帮助解决的问题。 (很多这段代码都是临时的,因此它会编译,以便我可以修复内存泄漏。)
问题在于我很确定我为节点分配了正确的空间量,我认为Valgrind确认了这一点,因为我只有2个未释放的块(365,371个分配中)。
无论如何,我将发布整个代码(以防任何人需要完整的上下文),但我认为相关的部分是加载函数和清除函数,我分别分配和释放内存。
==18981== HEAP SUMMARY:
==18981== in use at exit: 448 bytes in 2 blocks
==18981== total heap usage: 365,371 allocs, 365,369 frees, 81,843,792 bytes allocated
==18981==
==18981== 448 (224 direct, 224 indirect) bytes in 1 blocks are definitely lost in loss record 2 of 2
==18981== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==18981== by 0x4011B0: load (dictionary.c:111)
==18981== by 0x4008CD: main (speller.c:40)
==18981==
==18981== LEAK SUMMARY:
==18981== definitely lost: 224 bytes in 1 blocks
==18981== indirectly lost: 224 bytes in 1 blocks
==18981== possibly lost: 0 bytes in 0 blocks
==18981== still reachable: 0 bytes in 0 blocks
==18981== suppressed: 0 bytes in 0 blocks
相关的valgrind输出如下:
if (current_node->children[index] == NULL)
{
current_node->children[index] = malloc(sizeof(node));
// if we cannot allocate the memory, unload and return false
if (current_node->children[index] == NULL)
{
unload();
return false;
}
}
所以,我对这个输出的解释是,在下面的代码块中:
malloc
Function GroupString(s As String, groupSize As Long, _
Optional delim As String = ",", _
Optional prefix As String = "", _
Optional postfix As String = "") As String
Dim n As Long, m As Long, i As Long
Dim chunks As Variant
n = Len(s)
m = Int(n / groupSize)
If n Mod groupSize = 0 Then
ReDim chunks(0 To m - 1)
Else
ReDim chunks(0 To m) 'includes final chunk of size < groupSize
End If
For i = 0 To m - 1
chunks(i) = Mid(s, 1 + i * groupSize, groupSize)
Next i
If n Mod groupSize > 0 Then
chunks(m) = Mid(s, 1 + m * groupSize) 'final chunk
End If
GroupString = prefix & Join(chunks, delim) & postfix
End Function
语句(实际上是line dictionary.c:111)执行两次,以便永远不会释放分配的内存。 (这是正确的吗?)现在,这让我认为真正的问题在于我的明确功能,即它写得不好而且不能清除我的每个节点。
但是,我已经盯着代码几个小时,我几乎看不出它有什么问题。 (我确信很多;我对此并不太擅长。)
对此的任何帮助将不胜感激。
答案 0 :(得分:1)
首先:
代码错过了将成员数组children
初始化为每个节点NULL
的所有malloc()
。 malloc()
不对分配的内存执行任何初始化。它只包含“垃圾”。
所以这里
if (current_node->children[index] == NULL)
{
成为一个“随机”的决定,如果不是已经引发了未定义的行为。
(顺便说一句,“无效读/写”你的问题的标题提及,你没有告诉我们,很可能也提到上面的这一行代码......) < / p>
要解决此问题,您可以使用以下内容:
#include <stdlib.h> (/* for malloc() */
#include <errno.h> (/* for errno */
/* Allocate and initialises a new node. */
/* Returns 0 on success and -1 on failure. */
int node_create(node ** pn)
{
int result = 0; /* Be optimistic. */
if (NULL == pn)
{
errno = EINVAL;
result = -1;
}
else
{
node * n = malloc(sizeof *n);
if (NULL == n)
{
result = -1;
}
else
{
for (size_t i = 0; i < LETTERS; ++i)
{
n -> children[i] = NULL;
}
n -> is_word = 0;
(*pn) = n;
}
}
return result;
}
并像这样使用它:
...
if (-1 == node_create(&root))
{
perror("node_create() failed");
return false;
}