- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
在我因为没有看这里过多的 Valgrind 问题而崩溃之前:我看了。我花了很多时间寻找,但我发现的都是没有 malloc()
正确字节数的人。如果我不正确并且这是重复的,我很乐意接受您的引用。
在这个程序中,我使用树来创建拼写检查器。我的代码中有很多问题需要修复,但内存泄漏是我真正需要帮助解决的唯一问题。 (很多代码都是临时的,所以它会编译,以便我可以修复内存泄漏。)
问题是我相当确定我正在为我的节点分配正确的空间量,我认为 Valgrind 证实了这一点,因为我只有 2 个未释放的 block (在 365,371 个分配中)。
无论如何,我会发布完整的代码(以防有人需要完整的上下文),但我认为相关部分是加载函数和清除函数,我分别在其中分配和释放内存。
/**
* 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 输出如下:
==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
因此,我对此输出的解释是,在以下代码块中:
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
语句(确实是 dictionary.c:111 行)被执行两次,因此分配的内存永远不会被释放。 (这是正确的吗?)现在,这让我认为真正的问题在于我的 clear 函数,即它写得不好并且没有清除我的 trie 的每个节点。
但是,我盯着代码看了好几个小时,我几乎看不出它有什么问题。 (我敢肯定很多是;我只是不太擅长这个。)
如有任何帮助,我们将不胜感激。
最佳答案
对于初学者:
代码未将成员数组 children
初始化为每个节点 malloc()
的所有 NULL
。 malloc()
不对分配的内存执行任何初始化。它只是包含“垃圾”。
所以这里
if (current_node->children[index] == NULL)
{
成为一个“随机”决定,如果它本身没有引发未定义的行为的话。
(顺便说一句,您的问题标题中提到的“无效读/写”,但您没有向我们展示,很可能也恰好提到了上面的这一行代码...)
要解决此问题,您可以使用如下内容:
#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;
}
关于c - 内存泄漏和无效读/写,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39944782/
我有一个接受以下参数的函数: int setvalue(void (*)(void *)); 为了满足参数:void (*)(void *),我创建了这样一个函数: static void *
我有以下代码: typedef void VOID; int f(void); int g(VOID); 在 C 中编译得很好(在 Fedora 10 上使用 gcc 4.3.2)。与 C++ 编译的
这个问题已经有答案了: Is f(void) deprecated in modern C and C++? [duplicate] (6 个回答) 已关闭 7 年前。 B.A.T.M.A.N./A.
我在 ASP.NET Core 3.1 项目上有以下 Identity Server 4 配置: services .AddIdentityServer(y => { y.Events.R
我们有一个 O365 租户,一切都是开箱即用的。租户放置在德国云中,而不是全局 (office.de) 中。我们还开发了一个 Office 插件,使用 OAuth 2.0 授权访问共享点。首先,我们向
我有一个如下所示的路由 routes.MapRoute( name: "Default", url: "{controller}/{action}/{i
我正在尝试使用 OAuth2.0 访问 google 文档。我已经从 Google API 控制台获取了客户端 ID 和 key 。但是当我运行这段代码时,我收到了异常。如果我遗漏了什么,有人可以建议
此代码有效: let mut b: Vec = Vec::with_capacity(a.len()); for val in a.iter() { b.push(val); } 此代码不起作
使用 client_credintials 授权类型请求 EWS oauth2 v2.0 的访问 token 时出现错误。 https://login.microsoftonline.com/tena
我通过 Java 应用程序使用 Google 电子表格时遇到了问题。我创建了应用程序,该应用程序运行了 1 年多,没有任何问题,我什至在 Create Spreadsheet using Google
如何创建 匹配所有无效 Base64 字符的正则表达式?我在堆栈上找到了 [^a-zA-Z0-9+/=\n\r].*$ 但是当我尝试时我得到了带有 - 符号的结果字符串.我根本不知道正则表达式,任何人
我从 Gitlab CI/CD Pipelines 获得错误信息:yaml invalid。问题是由 .gitlab-ci.yml 脚本的第五行引起的: - 'ssh deployer@gita
我有 3 个数据源,设置如下: @Configuration @Component public class DataSourceConfig { @Bean("foo") @Conf
你好,我想用bulkCreate ex 插入数据: [ { "typeId": 5, "devEui": "0094E796CBFCFEF9", "application_name": "Pressu
UIApplicationExitsOnSuspend 不会强制我的应用程序退出。我已经清理过目标、删除了应用程序、重建并重新安装了很多次。 我确实需要退出我的应用程序。 最佳答案 您是否链接了 SD
在 iPhone 配置门户上,显示我的 iPhone 团队配置配置文件无效。有一个“由 Xcode 管理”文本。 “续订”按钮被禁用。 我该如何解决这个问题?谢谢 最佳答案 使用 Xcode 3.2.
好的,所以今天我用我们的“实时”数据库中的新信息更新了我的数据库……从那时起,我的一个表格就出现了问题。如果您需要任何代码,请告诉我,我将对其进行编辑并发布所需的代码... 我有一个报告表格,其中有一
我有一个结构体,其中有一个元素表示为 void (*func)(); 我知道 void 指针通常用于函数指针,但我似乎无法定义该函数。我不断收到取消引用指向不完整类型的指针。我用谷歌搜索了一下但没有结
我正在尝试使用 Coldfusion 9 从 ning 网络获取凭证,所以首先这是测试 api 的 curl 语法: curl -k https://external.ningapis.com/xn/
这个问题已经有答案了: Does C have references? (2 个回答) 已关闭 4 年前。 我正在学习 C 语言引用,这是我的代码: #include int main(void)
我是一名优秀的程序员,十分优秀!