内存泄漏使用C字符串

时间:2013-05-27 16:31:17

标签: c memory-management memory-leaks

我正在尝试在C中构建一个str_replace函数(以便学习C)。为了使事情变得更容易,我决定创建两个辅助函数,其中一个函数具有以下原型:

char * str_shift_right(const char * string, char fill, int32_t n);

它需要一个字符串,并在给定字符串中的fill位置添加字符n。这是完整的代码:

// replace the nth char with 'fill' in 'string', 0-indexed
char * str_shift_right(const char * string, char fill, int32_t n) {
    // +1 the null byte, +1 for the new char
    int32_t new_size = (int32_t) strlen(string) + 2;
    char * new_string = NULL;
    new_string = calloc(new_size, sizeof(char));

    new_string[new_size - 1] = '\0';
    int32_t i = 0;
    while (i < strlen(string) + 1) {
        // insert replacement char if on the right position
        if (i == n) {
            new_string[i] = fill;

        // if the replacement has been done, shift remaining chars to the right
        } else if (i > n) {
            new_string[i] = string[i - 1];

        // this is the begining of the new string, same as the old one
        } else {
            new_string[i] = string[i];
        }

        i++;
    }

    return new_string;
}

我想确保此功能没有泄漏内存,所以我尝试执行以下代码:

int main(int argc, const char * argv[])
{    
    do {
        char * new_str = str_shift_right("Hello world !", 'x', 4);
        printf("%s", new_str);
        free(new_str);
    } while (1);

    return 0;
}

然而,在使用活动监视器(Mac OSX应用程序,对于那些不熟悉的,有点像Windows上的进程管理器)观察内存使用情况时,看起来RAM很快被吃掉了,而且当它不可用时程序停止执行。

这是内存泄漏的原因吗?如果是这样,我做错了什么? free(new_str)调用不应该释放内存吗?

感谢您的帮助。

编辑1 :修正了PaulR发现的一个错误。问题依然存在。

4 个答案:

答案 0 :(得分:6)

  

似乎RAM很快被吃掉了,当程序停止执行时它就不可用了。

您正在考虑使用哪种RAM?系统中的总RAM使用量?

如果是这样,您所看到的可能是您的终端使用的内存 - 您的程序打印出来的每个字符都将被终端存储在RAM中(虽然它可能会开始丢弃东西在一定的限度)。再试一次,但这一次,阻止输出显示在终端:

./program > /dev/null

作为一般规则,无论您有多少内存泄漏,它都会在程序终止时自动释放。我无法发现你程序中的任何泄漏。

答案 1 :(得分:2)

free不应该向系统释放内存(例如使用munmap(2),因为malloc通常更喜欢重新使用以前的free - d内存而不是获取它来自内核(例如使用mmap

直觉是系统调用管理内存地址空间(即mmapmunmap)非常昂贵,因此大多数malloc&amp; free实现尽可能在内部重用内存。

如果您怀疑内存泄漏,请尝试valgrind(最新版本已移植到MacOSX)。当然,使用调试信息和所有警告(例如gcc -Wall -gclang -Wall -g)编译代码

答案 2 :(得分:2)

更新:您是如何衡量的?这在UNIX上是不可能的:“程序停止执行时”[memory]不可用“。也许你只是看错了号码?!?

我看不出哪里应该有记忆。尝试使用valgrind

等工具

上述无效写入已多次讨论过。也许你正在破坏内存管理信息。我已经看到C库只是在前面和/或在每个分配的内存块之后使用字节来跟踪分配的内存片段。所以也许你正在以这种方式调整大小并以这种方式削弱内存管理。实际上,使用valgrind 和类似的工具。

但是,您可能还想简化代码。

  1. 无论如何都不需要将你完全覆盖的内存归零。
  2. 当你知道这些位置时,不需要使用循环。
  3. 您还可以复制尾随\0
  4. 实际上 使用size_t无符号。如果fill为否定,则上述代码不会发出警告。使用size_t时,不得为负数。
  5. 所以这应该足够了(我没有编译测试这个 - 你可能想要):

    char* str_shift_right(const char* string, char fill, size_t n) {
      size_t len = strlen(string);
      char* new_string = malloc(len + 2, sizeof(char));
      memcpy(new_string, string, n);
      new_string[n] = fill;
      memcpy(new_string + n + 1, string + n, len - n + 1);
      return new_string;
    }
    

    最后memcpy也会在此处复制尾随\0。总的来说,C编译器可以更好地优化此代码,memcpy通常可以很好地处理。此外,它实际上更容易阅读。

答案 3 :(得分:0)

虽然已经提到过,但我认为值得强调的是,如果您怀疑程序中存在内存泄漏,请不要只是通过监视系统监视器而是使用 valgrind 来得出结论而不是。

从这里下载:

http://valgrind.org/downloads/current.html