【问题标题】:Potential memory leak?潜在的内存泄漏?
【发布时间】:2014-01-09 13:33:30
【问题描述】:

以下代码解决了去除字符串中重复字符的问题。

void removeDuplicatesEff(char *str) 
{
    if (!str)
        return;

    int len = strlen(str);
    if (len < 2)
        return;

    const int sz = (1<<CHAR_BIT); 
    bool hit[sz] = {false};

    int tail = 0;
    for (int i=0; i<len; ++i) 
    {
        if (!hit[str[i]]) 
        {
            str[tail] = str[i];
            ++tail;
            hit[str[i]] = true;
        }
    }

    str[tail] = 0;
}

在上一步设置str[tail]=0后,如果char *str确实包含重复字符,则其大小会更小,即tail。但我想知道这里是否存在内存泄漏?在我看来,以后我们无法释放分配给原始char *str 的所有空间。这是正确的吗?如果是这样,在这种情况下我们该如何解决?

【问题讨论】:

  • 我有一个问题,可能是一个愚蠢的问题,但我不明白你到底在用大小为 256 的数组做什么?它代表什么?
  • @Kraken 作为哈希表,记录char *中每个元素出现的频率。
  • @herohuyongto 是的,但为什么是 256?不应该是128吗?
  • @Kraken 通过考虑Extended ASCII Codes 来处理
  • @herohuyongtao 是的,C 标准要求CHAR_BIT&lt;limits.h&gt; 中定义为char 表示中的位数。它必须至少为 8,但理论上没有最大尺寸(N1570(C11 之前的草案)§5.2.4.2.1/1)。并且符号常量总是在可读性方面优于幻数。

标签: c++ c string memory-leaks


【解决方案1】:

在我看来,以后我们无法释放分配给原始 char *str 的所有空间。是这样吗?

没有。以零结尾的字符串的长度与分配的内存缓冲区的大小完全解耦,系统单独处理。只要每次分配后都进行对称释放(例如,每个malloc 操作都有一个free),你就安全了。

但我想知道这里是否存在内存泄漏?

可以说,是的,这仍然是一个泄漏,因为它(暂时)使用了比所需更多的内存。但是,这通常不是问题,因为内存最终会被释放。因此,除非在非常特殊的情况下,这不会被视为泄漏。

也就是说,代码是非常规的,而且肯定比必要的要长(它还假设 CHAR_BIT == 8 但那是另一回事)。例如,您可以更轻松地初始化标志数组,节省一个循环:

bool hit[256] = {false};

为什么你的循环会遍历字符串 one-based,为什么第一个字符是单独处理的?

【讨论】:

  • 那么free(str)会释放所有原本分配的空间吗?
  • 您的第二部分答案有点误导。在常用的术语中,内存泄漏是一个动态分配的对象,您不再有对其的引用。这里不是这种情况。
  • @Jens 这就是我使用“可以说”的原因。但是,是的,我会进一步澄清这一点。
  • @herohuyongtao 测试用例没有意义,因为它没有做你认为它做的事情。删除 a[4] = 0; 行,“长度”将始终为 4。它是指针的大小,而不是数组的长度。
  • @KonradRudolph 我刚刚意识到。真傻我。已删除。
【解决方案2】:

不,没有泄漏。您只需通过输入0 而不是其长度来修改数组的内容。

您也不应该通过for-loop 的赋值来初始化您的hit 数组。标准初始化

bool hit[256] = { 0 };

就足够了,并且可以由您的编译器替换为最有效的初始化形式。

【讨论】:

    【解决方案3】:

    在您的情况下没有内存泄漏。当您从头部分配内存并且在使用后未释放时,就会发生内存泄漏。在您的情况下,您没有从堆中分配任何内存。您正在使用存储在堆栈中并在控制从该函数返回时释放的局部变量。

    【讨论】:

      【解决方案4】:

      您所做的只是更改终止符的位置。它实际上并没有改变分配内存的大小。这其实是一个很普通的操作,而且不会有内存泄露的风险。

      【讨论】:

        【解决方案5】:

        不,您不会发生内存泄漏。在str 上执行delete []free() 将很好地释放所有分配的内存,因为该信息存储在其他地方并且不依赖于存储在str 中的数据类型。

        【讨论】:

          【解决方案6】:

          但我想知道这里是否存在内存泄漏?在我看来,后来我们无法释放分配给原始 char *str 的所有空间

          这里可能没有问题。 str 的存储空间已通过以下方式之一分配:

          • 堆栈上的保留空间
          • 堆上的malloc空间
          • 数据段中的保留空间。

          在第一种情况下,当堆栈帧展开时,所有空间都消失了。第二种情况,malloc 记录分配的字节数(通常在 malloc 返回值指向的第一个字节之前的内存位置。第三种情况,在程序第一次加载时只分配一次空间。

          那里没有泄漏的可能性。

          【讨论】:

            猜你喜欢
            • 2011-10-16
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2023-04-01
            相关资源
            最近更新 更多