2010-07-23 32 views
6

我有一个函数将一个指针作为参数重新分配给一个新的大小。现在,问题是 - 根据手册页 - realloc需要一个指针,该指针之前已由malloccalloc返回。如何确保调用者传递malloc'd指针?

如何确保调用者传递符合要求的指针? 似乎没有内置的C机制(如类型限定符或其他)来做到这一点。

现在,在我调整我的API之前(因为我认为现在的功能不够强大) - 请确认我没有错过任何东西?

在此先感谢。

编辑: 一种解决方案显然是在功能对malloc 。问题在于调用者没有“看到”分配。因此,我需要在文档中明确地说出他必须释放指针。这比预期他们提供malloc'd指针更糟糕(这意味着调用者必须释放它)。

我真正想要的是在编译时阻止滥用。那,还有一匹小马。 ;-)

+0

你需要使它真正是万无一失的? – Nyan 2010-07-23 14:43:06

+0

至少我想,是的 – RWS 2010-07-23 14:45:45

+0

因为你不能,你应该停止担心,做一些更有趣的事情。人们可以颠覆**任何**和**所有**您想要尝试的检查或预防。不要浪费时间来防止。投入大量的时间和清晰的声音,以便他们可以阅读错误信息并意识到他们的错误。 – 2010-07-23 17:04:07

回答

10

我怎样才能确保调用者传递满足这些要求的指针?

文档。

定义API。

如果编写调用者的人拒绝遵循API,事情就会崩溃。他们拒绝按照你的规则玩耍,事情也一塌糊涂。他们期待什么?

2

您无法确定指针指向的区域是否为[m|c]alloc();'d。你只能定义你的API,并希望你的API用户遵循它。

是否自己分配内存(被调用者)过高?如果您受此限制,您仍然可以使用realloc(NULL, size);进行初始分配。

有关您的问题的更多信息会很好。

0

您可以在函数中维护一个静态指针并自己调用realloc。返回静态指针。这样用户就不用担心分配或释放。当进程死亡时,变量将被自动释放。

请注意,如果realloc失败,它将返回一个空指针,但原始malloc的内存不变,这是内存泄漏的常见原因。

+0

这不回答问题。 – 2010-07-23 14:44:33

+2

不,但它是一个重要的注释,可能适用于任何答案,所以我提高了它,即使我更愿意说“if(tmp)a = tmp; else {注意失败但保持原样}” 。如果realloc失败,没有人应该尝试使用分配空间的“扩展”区域,但谁拥有指针之前应该是删除它的人。 – supercat 2010-07-23 15:42:29

4

在一天结束时,C中的指针只不过是一个机器字,它可能指向或不指向进程内存中的maningful数据,这些数据可能或不可能由malloc分配。没有这样的信息附加到任何指针。

只需向API添加一个大的胖警告即可。如果文档中明确指出“永远不会传递这个不是malloc'd的函数指针”,并且有人这样做,并且会发生错误/崩溃,这不是你的错 - 你无法在这里进行防御编程。

0

更改你的实现,所以你不使用realloc。如果传入的缓冲区太小,只需malloc一个更大的缓冲区,并将传入缓冲区的内容memcpy写入它。这会以牺牲性能的边际损失为代价来提高API的可用性。

+1

这更糟。现在你必须依靠调用者释放()新缓冲区。如果他们不这样做,它不会闹翻;它只会泄漏内存。如果您想防范不阅读API文档的用户,请不要以默默无闻的方式进行操作。 – nmichaels 2010-07-23 14:54:08

+0

@Nathon:如果你在一个API调用中重新分配一个指针,这个指针可能比mallocing新内存差得多。原来的指针现在可能是无效的,但如果程序员没有阅读API文档,他可能不知道,并决定写更多的数据。如果例如旧指针现在通过新的不同缓冲区,那么这很容易导致细微的数据损坏错误。 – JeremyP 2010-07-24 08:28:15

2

一种可能的方式。 摘要它。

foo.c 
#include "foo.h" 
struct foo{ 
    ... 
} ; 

foo *newFoo(...)   
void resize(foo *f)  

foo.h 

struct foo; 
typedef struct foo; 

caller.c 

foo *myfoo; 
myfoo = newFoo(..) 
resize(myfoo); 
+0

+1我想我只是回答了你已经做过的 – asr 2010-07-23 15:43:41

0

如果你已经是指针值,没有(标准)的方式,以确定该指针的值是由malloc()返回。如果您对平台上动态内存分配的工作方式有深入的了解,那么您可以根据指针值进行有根据的猜测,但即使这并不能保证您正在查看某个实际上是从malloc()返回的值而不是与之相抵的值(例如,*ptr = malloc(10); foo(&ptr[5]);)。

的一个策略,可能会或可能不会是值得的努力(IME,它不是)是隐藏malloc()realloc(),并free()背后某种内存管理器,用于跟踪分配的指针和大小。您的代码不会调用realloc(),而会调用内存管理器中的resize函数,如果传递给它的指针不在托管指针列表中,则该函数将返回错误代码。

2

用户应该如何获得这个malloc'ed指针在第一位?这不可能是你的API中的另一个函数获得的吗?否则,它听起来像样板代码给我,必须在调用你的函数之前用malloc分配一块内存。

在你的情况,我会尝试。让调用者通过一个函数获得一个有效的指针,我通过另一个函数提供并释放它。更好的是,将它们一起包裹在不透明的结构中。

my_param_type my_param = init_param(....); 
... 
my_function_that_wants_malloc(.....,my_param); 
... 
free_param(my_param); 

这对您的API有意义吗?

拥有自己的类型,即使对于最蹩脚的用户,他也必须通过预期的init_param()函数获得它。

0

创建一个自定义数据类型,它是一个重命名的空指针。

typedef void* myPointerType; 

写入一个分配函数(可为可围绕malloc一个简单的包装),该用户必须使用分配内存。

myPointerType myAllocateFunction (size_t size) { 
    return (myPointerType)(malloc(size)); 
} 

你也想做一个匹配的“免费”功能。

现在,您的函数(执行realloc的函数)将myPointerType对象作为参数而不是通用指针。您可以将其重新降至void*以与realloc一起使用。为了解决这个问题,用户必须手动将一个非malloc ed指针指向myPointerType,但是您可以在文档中指定不允许从myPointerType转换到myPointerType(因此如果他们这样做并且他们的应用程序崩溃了,因为他们滥用API)。

有更强大的方法可以执行此操作,但我不确定是否值得麻烦。你不能完全防止API(你会为近来有多愚蠢的人物感到惊讶)。无论您最终实施什么,确保API正确使用的最佳方式是提供清晰,全面的文档。

你是你自己的小马,对不起。

+0

当构建为静态/共享库时,该typedef是否在* .h文件中?对不起,新问题。 – 2012-04-11 23:11:24

+0

@ TristonJ.Taylor-如果这是共享库的公共接口的一部分,那么是的,它需要放在头文件中。否则,您将拥有引用尚未定义的类型的函数,并且您的用户将得到编译时错误。 – bta 2012-04-12 02:20:03

0

如果你正在寻找一个编译时检查,你唯一能做的就是声明一些新的类型,它是由“批准的”分配调用返回的。我建议是这样的:

 
typedef struct MEM_INFO {void *ptr; int allocsize; struct *privateMemInfo priv;} ALLOCMEM[0]; 

的privateMemInfo会在你的.c文件中定义,而不是头部,从而一定程度上保护领域中它的恶作剧。请注意,因为ALLOCMEM将是一个数组类型,所以ptr和allocsize总是使用箭头运算符而不是点来访问。一个将ALLOCMEM作为参数的例程自然会被赋予一个指向ALLOCMEM的指针,从而允许它“很好地”执行重定位。因此,例如,一个会用:

 
    ALLOCMEM foo = {0}; 
    if (reallocate(foo,12345) >= 0) /* It worked */ 
+0

好主意在这里,但:typedef char * strptr;皇家击败你! strptr可以转换为char *,并且CPP将在编译/设计时捕获错误。在有人试图颠覆这种情况下,哦,是的,realloc将自行失败。好想法。谢谢。我认为它是我自己和操作者真正想要的。 – 2012-04-11 00:15:28

+0

我的声明是错误的,因为它需要是ALLOCMEM [1],但基本思想是所有的分配例程都需要对“struct MEM_INFO”的引用。尽管没有任何东西可以防止代码与“struct MEM_INFO”的内容混淆,但编译时检查将确保只有对这样的结构的引用才能传递给分配/释放例程。 – supercat 2012-04-11 19:59:21