我今天编写了以下代码来试验返回指向已分配内存的指针。 该计划工作正常,但我有几个问题:
要为rmch
的返回值分配内存,我使用realloc
。我理解函数及其作用大部分我只是不确定行(char *)
中ret = (char *) realloc(ret, c * sizeof(char));
的含义我明白realloc(ret, c * sizeof(char));
将分配的内存调整为# c chars,但(char *)
部分做了什么?
我没有释放ret
指向任何地方的已分配内存,但我释放了指向ret
函数中调用的main
的指针。分配的内存发生了什么?如果它没有被释放,我将如何释放它?
代码
#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;
}
答案 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)
malloc
或calloc
将为您提到的大小分配内存。 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 *
,malloc
或calloc
)对于操作系统来说始终是一项代价高昂的操作。因此,不要在realloc
次调用realloc
,而是使用n
仅分配一次内存,这样性能就会很好。