【问题标题】:Figuring out issues raised by valgrind找出 valgrind 提出的问题
【发布时间】:2015-04-04 17:46:02
【问题描述】:

我试图通过分配所需的内存加 1 并将最后一个元素设置为 -1 来获取 C 中整数数组的大小。然后我创建了一个名为 getSize 的函数来确定数组中这个 -1 元素之前的元素数量,这是代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int getSize(int * array)                                                        
{                                                                               
    int i=0;                                                                    
    while(1)                                                                    
    {                                                                           
        if(array[i] ==  -1) return i;                                           
        else i++;
    }
}

int main()
{
    int * array = malloc(sizeof(int)*5);
    memset(array,0,5);
    array[4] = -1;
    printf("\nsize = %d\n",getSize(array));
    return 0;
}

这只是一个测试代码,但函数 getSize 是更大代码的一部分,我在这段代码上运行了 valgrind,这就是我遇到的问题:

==1683== 条件跳转或移动取决于未初始化的值
==1683== 在 0x100000EAE: getSize (in ./a.out)
==1683== by 0x100000F2E: main (in ./a.out)

总结如下:

==1683== 堆摘要:
==1683== 在退出时使用:425 个块中的 38,676 个字节
==1683== 总堆使用量:508 次分配,83 次释放,44,948 字节分配

泄漏摘要:
==1683== 肯定丢失:2 个块中的 36 个字节
==1683== 间接丢失:0 个块中的 0 个字节
==1683== 可能丢失:119 个块中的 13,130 个字节
==1683== 仍然可以访问:304 个块中的 25,510 个字节
==1683== 抑制:0 个块中的 0 个字节
==1683== 错误摘要:来自 20 个上下文的 22 个错误(抑制:0 来自 0)

【问题讨论】:

  • memset() 以字节为单位,你需要memset(array, 0, 5*sizeof(int))
  • 更正了 memset 但仍然存在同样的问题。
  • 所有问题都还存在吗?您可以在printf() 之后通过free()ing array 来消除内存泄漏,但应该修复未初始化的警告。你重新编译了吗?

标签: c malloc valgrind


【解决方案1】:

这段代码有几个问题。您显示的 valgrind 输出突出显示了两个问题。

==1683== 条件跳转或移动取决于未初始化的值
==1683== 在 0x100000EAE: getSize (in ./a.out)
==1683== by 0x100000F2E: main (in ./a.out)

这是由 getSize() 中的 if 语句触发的

if(array[i] ==  -1) return i;  

这乍一看似乎应该没问题;在 main 函数中,您使用 malloc 分配内存,然后使用 memset 将其归零,然后将最后一个元素设置为 -1。

但是,让我们仔细看看

    int * array = malloc(sizeof(int)*5);
    memset(array,0,5);

您已分配足够大的空间来容纳 5 个整数,因此可能是 20 个字节。然后您尝试对此进行 memset,但是 memset 当时对一个字节进行操作 - 换句话说,大小应该是以字节为单位的长度,而不是整数。 因此,在此操作之后,您将 5 个字节归零。其余内存仍未初始化。

接下来,您使用数组表示法将最后一个整数设置为 -1。这意味着您有一个 20 字节的缓冲区,其中前 5 个字节和后 4 个字节已初始化。

回到您的 getSize 函数,for 循环中的第一次迭代很好,但是第二次、第三次和第四次迭代正在读取未初始化的字节,并基于此执行条件跳转。

我们可以在 valgrind 输出中看到的第二个错误是内存泄漏。

泄漏摘要:
==1683== 肯定丢失:2 个块中的 36 个字节
==1683== 间接丢失:0 个块中的 0 个字节
==1683== 可能丢失:119 个块中的 13,130 个字节
==1683== 仍然可以访问:304 个块中的 25,510 个字节
==1683== 抑制:0 个块中的 0 个字节
==1683== 错误摘要:来自 20 个上下文的 22 个错误(抑制:0 来自 0)

在绝对丢失部分,它告诉我们您在 2 个块中丢失了 36 个字节。您提供的代码中实际上只有一个泄漏,即为array 分配的内存。你需要添加这一行:

free(array);

在从您的函数返回之前。 Valgrind 可以为您提供有关内存泄漏的更多详细信息 - 在输出中查找提示。

【讨论】:

    猜你喜欢
    • 2013-10-07
    • 1970-01-01
    • 1970-01-01
    • 2016-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-07
    • 1970-01-01
    相关资源
    最近更新 更多