如何从另一个功能释放分配的内存

时间:2012-08-02 19:29:45

标签: c function pointers char free

我今天编写了以下代码来试验返回指向已分配内存的指针。 该计划工作正常,但我有几个问题:

  1. 要为rmch的返回值分配内存,我使用realloc。我理解函数及其作用大部分我只是不确定行(char *)ret = (char *) realloc(ret, c * sizeof(char));的含义我明白realloc(ret, c * sizeof(char));将分配的内存调整为# c chars,但(char *)部分做了什么?

  2. 我没有释放ret指向任何地方的已分配内存,但我释放了指向ret函数中调用的main的指针。分配的内存发生了什么?如果它没有被释放,我将如何释放它?

  3. 代码

    #include <stdio.h>
    #include <stdlib.h>
    char* rmch(char *str, char ch)
    {
        char *ret = NULL;
        int c = 0, i;
    
        for(i = 0; str[i] != '\0'; i++)
        {
            if(str[i] != ch)
            {
                c++;
                ret = (char *) realloc(ret, c * sizeof(char));
                ret[c - 1] = str[i];
            }
        }
        ret[c] = '\0';
        return ret;
    }
    
    int main(void)
    {
        char *foo = rmch("f o o", ' ');
    
        printf("%s", foo);
        free(foo);
        return 0;
    }
    

3 个答案:

答案 0 :(得分:2)

在主游戏中释放Foo将释放你在rmch中重新分配的视频。

原因是free()转到rmch返回的指针所指定的地址。

此外,由于您使用“C”标记标记了此帖子,因此您绝不应该转换分配的返回值。 void *'s是自动的,隐式地提升为它们存储的任何内容,前提是它们在分配期间被赋予了正确的字节大小。

顺便说一句,你不应该直接将任何已分配的内存直接存储到正在使用/将要使用的指针中,因为如果返回的指针为NULL并且你仍指向旧内存,这可能导致内存泄漏。

最好这样做:

temp = realloc();
if( temp == NULL)
{
     printf("realloc failed to reallocated memory!");
     return NULL;
}
ret = temp;

然后你还需要在主体中检查NULL返回。

答案 1 :(得分:1)

您的代码还有一个问题,当您使用valgrind运行它时,您会得到类似的结果:

toc@UnixServer:~$valgrind --leak-check=full --show-reachable=yes ./realloc_pb
==17077== Memcheck, a memory error detector
==17077== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==17077== Using Valgrind-3.6.1-Debian and LibVEX; rerun with -h for copyright info
==17077== Command: ./realloc_pb
==17077== 
==17077== Invalid write of size 1
==17077==    at 0x80484BF: rmch (realloc_pb.c:19)
==17077==    by 0x80484E3: main (realloc_pb.c:25)
==17077==  Address 0x41b709b is 0 bytes after a block of size 3 alloc'd
==17077==    at 0x402896C: realloc (vg_replace_malloc.c:525)
==17077==    by 0x804848A: rmch (realloc_pb.c:14)
==17077==    by 0x80484E3: main (realloc_pb.c:25)
==17077== 
==17077== Invalid read of size 1
==17077==    at 0x402903D: __GI_strlen (mc_replace_strmem.c:284)
==17077==    by 0x4098739: puts (ioputs.c:37)
==17077==    by 0x4050112: (below main) (libc-start.c:226)
==17077==  Address 0x41b709b is 0 bytes after a block of size 3 alloc'd
==17077==    at 0x402896C: realloc (vg_replace_malloc.c:525)
==17077==    by 0x804848A: rmch (realloc_pb.c:14)
==17077==    by 0x80484E3: main (realloc_pb.c:25)
==17077== 
foo
==17077== 
==17077== HEAP SUMMARY:
==17077==     in use at exit: 0 bytes in 0 blocks
==17077==   total heap usage: 3 allocs, 3 frees, 6 bytes allocated
==17077== 
==17077== All heap blocks were freed -- no leaks are possible
==17077== 
==17077== For counts of detected and suppressed errors, rerun with: -v
==17077== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 11 from 6)

因为你需要为null终止的char分配更多的空间,所以也要修改它:

temp = (char *) realloc(ret, (c + 1) * sizeof(char)); // It's better to use temp pointer as suggested by ardent sonata

最后一件事是关于cast malloc或realloc函数它并不是必需的,如果你忘了添加正确的标题(stdlib.h),它对编译器很有用,所以他可以警告你(http://c-faq.com/malloc/mallocnocast.html )。

希望得到这个帮助。

问候。

答案 2 :(得分:0)

malloccalloc将为您提到的大小分配内存。 realloc将调整已分配的内存大小,可以缩小或扩展现有的堆缓冲区。

例如,如果我们将现有堆缓冲区从n字节扩展到n+1字节 意味着我们必须像realloc(existing_bufPtr, n+1)一样调用realloc。现在,OS必须将现有缓冲区增加一个字节,因此它将检查来自n+1的{​​{1}}字节是否未分配给任何其他目的。如果是,它只会将现有缓冲区的大小扩展为existing_bufPtr,否则它将在单独的位置分配新缓冲区,并将值从现有缓冲区移动到新缓冲区。然后它将返回新分配的缓冲区的起始地址。

所以我们必须检查返回地址是否与我们传递的相同,如果它们不相同,我们必须释放前一个缓冲区。所以改变你的代码如下

n+1

使用if(str[i] != ch) { c++; ret_new = (char *) realloc(ret, c * sizeof(char)); if (NULL == ret_new) { return NULL; } else if (ret_new != ret) { free(ret); ret = ret_new; } ret[c - 1] = str[i]; } 缩小现有堆缓冲区将不会返回新的地址。但扩张可能会回归新的地址。

realloc会将指针类型返回为realloc,我们必须将其输入到我们的指针类型void *

内存分配功能(char *malloccalloc)对于操作系统来说始终是一项代价高昂的操作。因此,不要在realloc次调用realloc,而是使用n仅分配一次内存,这样性能就会很好。