c - 由于释放内存导致的 Valgrind 错误?
问题描述
我收到了这些 Valgrind 错误,但真的不知道我做错了什么。我假设我正在使用指向空闲内存位置的指针。有什么帮助吗?
Node* insertNode(Node *root, int value){
if(!root) {
root = malloc(sizeof(struct Node));
root->data = value;
root->left = root->right = NULL;
}
else if(value > root->data && root->right) {
insertNode(root->right, value);
}
else if(value > root->data && !root->right) {
root->right = insertNode(root->right, value);
}
else if(root->left) {
insertNode(root->left, value);
}
else {
root->left = insertNode(root->left, value);
}
return root;
}
Node* deleteNode(Node *root, int value) {
if (root == NULL)
return root;
else if (value < root->data) {
root->left = deleteNode(root->left, value);
}
else if (value > root->data) {
root->right = deleteNode(root->right, value);
}
else if (root->left == NULL) {
Node *temp;
temp = root->right;
free(root);
return temp;
}
else if (root->right == NULL) {
Node *temp;
temp = root->left;
free(root);
return temp;
}
else {
Node *temp;
temp = smallestNode(root->right);
root->data = temp->data;
root->right = deleteNode(root->right, temp->data);
}
return root;
}
Node* freeSubtree(Node *N) { if(!N) return;
freeSubtree(N->left);
free(N);
freeSubtree(N->right);
}
解决方案
自己捕获其中一些内容的一种方法是,始终将任何已释放的指针设为空,这样它就不会有一个挥之不去的引用。
Node* freeSubtree(Node *N) { if(!N) return;
freeSubtree(N->left);
free(N); N = NULL; // NULL out the pointer!
freeSubtree(N->right);
}
当然@Johnny Mopp 已经指出了需要您将其移到free()
最后的实际错误。
实际上,对于这样的代码,我在 C 中使用任何可能通过传递指针地址来释放内存的函数变得更加激进,因此地址本身可以在调用者中被清空。
Node *freeSubtree(Node **PN)
{
if (!PN || !*PN) return;
freeSubtree( &( (*PN)->left) ); // frees and NULLs the ->left pointer
freeSubtree( &( (*PN)->right) ); // frees and NULLs the ->right pointer
free(*PN);
*PN = NULL; // NULL the *caller's* handle on the pointer
}
如果你想使用这种技术,你真的必须全力以赴,因为指针地址参数通常非常普遍,但永远不会有释放后使用错误是天赐之物。
编辑:释放后使用错误并不总是错误,有时它们是安全错误。
注意:在 C++ 中,您可以使用 ref 参数来提高可读性。
推荐阅读
- javascript - 如何使用 JS 从 JIRA 中提取数据?
- android - 带有 Headers 参数的 Retrofit POST 请求的 404 响应
- c# - 在构建服务器上将 C++ dll 构建到两个平台 (x86+x64)
- c# - 如何使用 C# 勾选“TLS 1.2”(Internet 选项> 高级设置> 安全> TLS 1.2)
- typescript - Eslint 找不到 webpack 别名的路径
- python - Pandas - 在同一列中格式化不同格式的日期列
- go - 无法组装交易,err 提案响应不成功,错误代码 500,msg 链码注册失败:容器以 0 退出
- java - 如何保存 LinkedList 的实例状态
在 recyclerView 中,所以它不会在旋转设备上破坏? - php - Laravel 使用 middlware 设置配置值
- javascript - typescript声明合并中的导出接口和导出默认接口有什么区别?