潜在的内存泄漏?

3
以下代码解决了在字符串中删除重复字符的问题。
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
@herohuyongto 是啊,但为什么是256?不应该是128吗? - Kraken
@herohuyongto 我可能搞错了什么大事,但每个字符只能有ASCII码0-127对吧? - Kraken
1
@Kraken 为了处理 ,需要考虑使用扩展ASCII码 - herohuyongtao
1
@herohuyongtao 是的,C标准规定<limits.h>中定义了CHAR_BIT,它表示char类型的位数。它必须至少为8,但在理论上没有最大值(N1570(C11之前的草案)§5.2.4.2.1/1)。对于可读性而言,符号常量总是优于魔法数字。 - Casey
显示剩余4条评论
6个回答

3
在我看来,我们不能释放分配给原始char *str的所有空间,这是正确的吗?
不。零终止字符串的长度与分配的内存缓冲区的大小完全解耦,并且系统单独处理它们。只要每次分配后都跟随对称的释放(例如,每个malloc操作都有一个free),你就是安全的。
但我在想这里是否存在内存泄漏?
可以说是的,这仍然是一种泄漏,因为它(暂时)使用了比所需更多的内存。然而,通常情况下这不是问题,因为内存最终会被释放。除非在非常特殊的情况下,否则这不会被视为泄漏。
话虽如此,该代码相当不寻常,并且明显比必要的长(还假设CHAR_BIT == 8,但那是另一回事)。例如,您可以更轻松地初始化您的标志数组,从而节省一个循环:
bool hit[256] = {false};

为什么你的循环以字符串的第一个字符作为起点,而且为什么要单独处理第一个字符?


1
你的第二个回答有点误导人。在常用的术语中,内存泄漏是指动态分配的对象没有被引用。但这里并不是这种情况。 - Jens Gustedt
@Jens 这就是为什么我使用“可以说”的原因。但是,是的,我会更明确地解释这一点。 - Konrad Rudolph
@herohuyongtao 这个测试用例没有意义,因为它并不做你认为它做的事情。移除 a[4] = 0; 这一行,"length" 将始终为 4。这是指针的大小,而不是数组的长度。 - Konrad Rudolph
@KonradRudolph 我刚意识到。我真蠢。已删除。 - herohuyongtao
@KonradRudolph 我知道了,我会按照你建议的去做。谢谢。 - herohuyongtao
显示剩余6条评论

2
不,没有泄漏。您只需将0放入数组中而不是其长度即可修改数组的内容。
此外,您不应通过for循环赋值来初始化hit数组。标准初始化方法为:
bool hit[256] = { 0 };

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


2

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


1
你所做的只是改变终止符字符的位置。这并不会实际改变分配的内存大小。这是一个非常常见的操作,而且这样做没有内存泄漏的风险。

1
不,你不会有内存泄漏问题。对str执行delete []free()将很好地释放所有已分配的内存,因为该信息存储在其他地方,不依赖于存储在str中的数据类型。

1
但我在想这里是否存在内存泄漏?在我看来,后来我们不能释放分配给原始char *str的所有空间。 这里可能没有问题。str的存储方式有以下几种之一: 保留堆栈上的空间 malloc在堆上分配空间 数据段中保留空间。 在第一种情况下,当堆栈帧展开时,所有空间都会消失。在第二种情况下,malloc记录分配的字节数(通常在malloc返回值指向的第一个字节之前的内存位置)。在第三种情况下,空间仅在程序首次加载时分配。 没有泄漏的可能性。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接