![](/img/trans.png)
[英]How would I go about freeing this malloc in order to prevent any memory leaks when using valgrind
[英]Valgrind - Memory Leaks When Duplicating/Freeing Arrays
我在弄乱分配和释放内存以获取更多信息。 下面,我从命令行( char **argv
)接收字符串参数,并尝试将它们作为大写字符串复制到另一个malloc数组中:
static char **duplicateArgs(int argc, char **argv) {
if (argc <= 1) {
printf("%s\n", "No strings to duplicate.");
exit(1);
}
char **duplicate = (char**)malloc((argc + 1) * sizeof(char**));
int i = 1;
int j = 0;
int stringLength;
while (argv[i]) {
stringLength = strlen(argv[i]);
duplicate[i] = (char*)malloc(stringLength * sizeof(char) + 1);
for (j = 0; j < stringLength; j++) {
duplicate[i][j] = toupper(argv[i][j]);
}
duplicate[i][j]= '\0';
i++;
}
duplicate[i] = NULL;
return duplicate;
}
我也有释放它们的功能:
static void freeDuplicateArgs(char **copy) {
int i = 0;
while (copy[i]) {
if (copy[i] != NULL){
free(copy[i]);
}
i++;
}
if (copy != NULL){
free(copy);
}
}
在main
函数中,我调用以下方法,将它们打印出来,然后释放它们:
char **copy = duplicateArgs(argc, argv);
char **p = copy;
argv++;
p++;
while(*argv) {
printf("%s %s\n", *argv++, *p++);
}
freeDuplicateArgs(copy);
return 0;
输出按预期工作,定期打印出字符串,然后大写输出。 但是,当我对Valgrind进行检查时,会遇到以下麻烦:
==20867== Conditional jump or move depends on uninitialised value(s)
==20867== at 0x100000D1A: freeDuplicateArgs (part2.c:32)
==20867== by 0x100000E19: main (part2.c:57)
==20867==
==20867==
==20867== HEAP SUMMARY:
==20867== in use at exit: 62,847 bytes in 368 blocks
==20867== total heap usage: 520 allocs, 152 frees, 66,761 bytes allocated
==20867==
==20867== LEAK SUMMARY:
==20867== definitely lost: 8,639 bytes in 18 blocks
==20867== indirectly lost: 1,168 bytes in 5 blocks
==20867== possibly lost: 4,925 bytes in 68 blocks
==20867== still reachable: 48,115 bytes in 277 blocks
==20867== suppressed: 0 bytes in 0 blocks
如果编译器没有为我的freeDuplicates方法引发任何错误并且我的输出正常,为什么会出现这样的内存混乱情况?
编辑:我还应该提到我在OSX 10.8上-显然Valgrind与此有关。
您的释放代码很有趣-并非完全错误,但也并非完全正确:
static void freeDuplicateArgs(char **copy) {
int i = 0;
while (copy[i]) {
if (copy[i] != NULL){
free(copy[i]);
}
i++;
}
if (copy != NULL){
free(copy);
}
}
您可以在释放copy != NULL
之前测试copy != NULL
,但是一直以来都在使用它,因此该测试在那里很多余。 此外,您可以执行free(NULL)
而不会遇到问题。
然后我们看一下循环:
while (copy[i] != NULL)
{
if (copy[i] != NULL)
循环条件和if条件相同-同样,您可以free(NULL)
。
您的while循环具有写出的for循环结构。 您最好在以下方面做得更好:
static void freeDuplicateArgs(char **copy)
{
if (copy != NULL)
{
for (int i = 0; copy[i] != NULL; i++)
free(copy[i]);
free(copy);
}
}
copy != NULL
的测试可防止崩溃,并且仅在已知为非null时释放它,这是(非常非常)小的优化。
我怀疑这是问题的直接起因(稍后我会在其余的代码中看起来有点困难),但这是要考虑的问题。
你有:
static char **duplicateArgs(int argc, char **argv) {
if (argc <= 1) {
printf("%s\n", "No strings to duplicate.");
exit(1);
}
首先,可以在没有用户参数的情况下调用程序,但是它仍然具有argv[0]
,程序名称和NULL指针。 您的代码可能应该通过返回(char **)NULL
简单地处理负值。 对于0参数,您将返回一个指向空指针的指针。 对于一个或多个参数,需要做的工作。
考虑这一行:
duplicate[i] = (char*)malloc(stringLength * sizeof(char) + 1);
您可能会考虑两种情况: sizeof(char) == 1
和sizeof(char) > 1
(是的,请稍等-等待!)。 如果sizeof(char) == 1
,那么您不需要乘以它。 如果sizeof(char) > 1
,则说明您没有分配足够的空间。 表达式应为(stringLength + 1) * sizeof(char)
。 因此,编写以下两行之一:
duplicate[i] = (char*)malloc((stringLength + 1) * sizeof(char));
duplicate[i] = (char*)malloc(stringLength + 1);
我注意到C标准说定义为sizeof(char) == 1
,所以实际结果是相同的,但是如果您正在处理int
或其他sizeof(type)
数组,请在右侧获取与sizeof(type)
相乘的值这个地方可能很关键。
ISO / IEC 9899:2011§6.5.3.4中
sizeof
和_Alignof
运营商¶4当将
sizeof
应用于类型为char
,unsigned char
或signed char
(或其限定版本)的操作数时,结果为1。
以您的代码几乎与问题中的代码相同:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static char **duplicateArgs(int argc, char **argv)
{
if (argc <= 1) {
printf("%s\n", "No strings to duplicate.");
exit(1);
}
char **duplicate = (char**)malloc((argc + 1) * sizeof(char**));
int i = 0;
int j = 0;
int stringLength;
while (argv[i]) {
stringLength = strlen(argv[i]);
duplicate[i] = (char*)malloc(stringLength * sizeof(char) + 1);
for (j = 0; j < stringLength; j++) {
duplicate[i][j] = toupper(argv[i][j]);
}
duplicate[i][j]= '\0';
i++;
}
duplicate[i] = NULL;
return duplicate;
}
static void freeDuplicateArgs(char **copy)
{
int i = 0;
while (copy[i]) {
if (copy[i] != NULL){
free(copy[i]);
}
i++;
}
if (copy != NULL){
free(copy);
}
}
int main(int argc, char **argv)
{
char **copy = duplicateArgs(argc, argv);
char **p = copy;
argv++;
p++;
while(*argv) {
printf("%s %s\n", *argv++, *p++);
}
freeDuplicateArgs(copy);
return 0;
}
(区别是在本工作代码中为int i = 0;
而不是问题代码中为int i = 1;
)
在valgrind
下运行时,这将获得干净的健康单:
$ gcc -O3 -g -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition mlk.c -o mlk
$ valgrind ./mlk nuts oh hazelnuts
==582== Memcheck, a memory error detector
==582== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==582== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==582== Command: ./mlk nuts oh hazelnuts
==582==
nuts NUTS
oh OH
hazelnuts HAZELNUTS
==582==
==582== HEAP SUMMARY:
==582== in use at exit: 18,500 bytes in 33 blocks
==582== total heap usage: 38 allocs, 5 frees, 18,564 bytes allocated
==582==
==582== LEAK SUMMARY:
==582== definitely lost: 0 bytes in 0 blocks
==582== indirectly lost: 0 bytes in 0 blocks
==582== possibly lost: 0 bytes in 0 blocks
==582== still reachable: 18,500 bytes in 33 blocks
==582== suppressed: 0 bytes in 0 blocks
==582== Rerun with --leak-check=full to see details of leaked memory
==582==
==582== For counts of detected and suppressed errors, rerun with: -v
==582== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)
$
如您所见,没有报告内存错误。 对于该机器,仍在使用的33个块是“正常”的; 它们是由Mac OS XC运行时库分配的。 我还没有在Mac OS X 10.8系统上使用valgrind
进行比较。 我建议您尝试在valgrind
下运行一个非常简单的程序,看看它能告诉您什么:
int main(void) { return 0; }
这将是您系统的基准。 如果存在泄漏,则泄漏不是由您的代码引起的,并且您将需要学习如何记录抑制,以便您的程序不会因操作系统的违背行为而受到惩罚。
如果您在上面运行了简单程序,发现它不会产生泄漏(或者泄漏从根本上变得越来越小),那么请尝试一些更复杂的程序:
#include <stdlib.h>
int main(void)
{
void *vp = malloc(32);
free(vp);
return(0);
}
这样可以确保将malloc()
拖入并使用,但显然不会泄漏(它也可以正确处理malloc()
失败!)。
valgrind
对Mac OS X 10.8的支持 Valgrind网站说:
2012年9月18日:valgrind-3.8.1,用于X86 / Linux,AMD64 / Linux,ARM / Linux,PPC32 / Linux,PPC64 / Linux,S390X / Linux,MIPS / Linux,ARM / Android(2.3.x及更高版本),提供X86 / Android(4.0和更高版本),X86 / Darwin和AMD64 / Darwin(Mac OS X 10.6和10.7,对10.8的支持有限)。
您所看到的可能是对Mac OS X 10.8的有限支持的一个方面。
我看到我需要为自己重建valgrind
(3.7.0不是最新的)。
我认为您永远不会将freeDuplicateArgs
duplicate[0]
设置为任何值,所以当您在freeDuplicateArgs
使用copy[i]
时(从i = 0开始),您将不知道会发生什么。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.