给出一个函数声明:
void foo(void *ptr);
我无法更改功能的签名。 现在我需要在foo中分配内存,从ptr开始。 如果我写:
void foo(void *ptr) {
ptr = malloc(NUM * sizeof(TYPE));
}
当我用它调用时,它实际上并没有改变指针的内容:
void *myPtr = NULL;
foo(myPtr);
我知道我将myPtr的副本传递给foo()的原因。
我需要做的是将输入参数声明为指针的引用:
foo(void *& ptr) {
ptr = malloc(...);
}
但是,我无法将输入类型从(void *)更改为(void *&)。 我该如何解决这个问题?
我忘记了返回值不是签名的一部分,是的,我无法改变返回。
我认为我不能在C ++中这样做。我必须在此函数之外分配内存。
答案 0 :(得分:1)
如果不更改功能签名或呼叫站点,则无法实现所需。即一个非常肮脏的黑客将是:
void foo(void *ptr) {
*((void **)ptr) = malloc(NUM * sizeof(TYPE));
}
int main() {
void *myPtr = NULL;
foo(&myPtr);
}
但是,对于大多数情况(特别是,如果您不想更改现有的调用站点),如果编写一个能够执行所需操作的新函数并使foo
成为包装器,则可能会更好。对于它(反之亦然,取决于foo之前应该做的事情):
void new_foo (void*& ptr ) {
// ... whatever came before in the original foo
ptr = malloc(NUM * sizeof(TYPE));
// ... whatever came after in the original foo
}
void foo (void* ptr) {//<-- called on old call sites
void * tptr=ptr;
new_foo(tptr);
// free(tptr) ?
}
int main() {
void* ptr2=NULL;
foo(ptr1) //<- old call site)
//...
void* ptr2=NULL;
new_foo(ptr2); //<- new call site
}
答案 1 :(得分:-1)
如果您可以将代码移至/ {和foo
,而不更改其签名,这对您的用例是可行的,您可以执行类似的操作...
void underlying_foo(void *ptr)
{
// Do the stuff.
}
void foo(void *ptr)
{
ptr = malloc(...);
underlying_foo(ptr);
}
void new_foo(void **ptr)
{
*ptr = malloc(...);
underlying_foo(*ptr);
}
如果你不想/不能用foo
扭曲太多,那么你可以使用这样一个丑陋的解决方法......
#include <cstddef>
static void **trap_malloc_trap = nullptr;
void trap_malloc_set(void **trap)
{
trap_malloc_trap = trap;
}
void trap_malloc_unset()
{
trap_malloc_trap = nullptr;
}
void *trap_malloc(size_t size)
{
void *ptr = malloc(size);
if(trap_malloc_trap != nullptr)
*trap_malloc_trap = ptr;
return ptr;
}
void foo(void *ptr)
{
ptr = trap_malloc(NUM * sizeof(TYPE));
// Whatever else goes here...
}
则...
#include "foo_header.h"
int main()
{
void *some_pointer;
trap_malloc_set(&some_pointer):
foo(some_pointer);
trap_malloc_unset();
return 0;
}
这样,任何调用原始函数的代码仍然可以工作,需要检索指针的新代码可以使用trap_foo()
。
你可以使用另一个。它更快/更紧,但它会破坏任何依赖现有API的现有代码......
void foo(void *trap_ptr)
{
void **ptr = (void**)trap_ptr;
*ptr = malloc(NUM * sizeof(TYPE));
// Et cetera...
}
则...
void hacky_foo(void **ptr)
{
foo((void*)ptr);
}
int main()
{
void *the_pointer;
hacky_foo(&the_pointer);
return 0;
}
答案 2 :(得分:-1)
你真的应该把它标记为C问题 - 这种类型的void *指针tomfoolery在C ++中不受欢迎。虽然它是语言的一部分,并且偶尔会有其用途,但您可以更幸运地从寻找C问题的人那里获得所需的专业知识。
继续你的问题,我认为你想要做的事情(至少你发布的例子)根本不可能 - 具体来说:
dnvm upgrade
dnvm restore
考虑一下你在这里做了什么。你声明了一个带有void *类型的变量myPtr,并为它赋予了一个占位符值 - 一个无效的内存区域C程序员调用NULL,它通常为0(C ++程序员更喜欢nullptr,这是一种特定类型,提供一些安全性好处)。
现在你将它传递给foo:
void *myPtr = NULL;
foo(myPtr);
foo收到一个NULL指针 - 一个无效的内存地址,通常为0.当你调用void foo(void *ptr) {
ptr = malloc(NUM * sizeof(TYPE));
}
语句时,你的变量ptr = malloc(...)
获取malloc返回的内存地址的值 - 为您分配了一些内存,并将指向的地址返回到该内存。
您尚未修改变量myPtr的内容,该变量包含无效的内存地址NULL。
您需要更改函数的签名,以便它可以使用有效地址填充myPtr - 您刚刚分配的内存的地址。你可以这样做:
ptr
我没有看到任何其他方法。顺便说一下,我更喜欢选项1,因为在阅读时它最清楚发生了什么:
1: void* foo(void* ptr) { return malloc(...);} // return the address.
2: void foo(void** ptr) { *ptr = malloc(...);} // ptr to ptr.
3: void foo(void*& ptr) { ptr = malloc(...);} // C++: reference to ptr.
除非你在foo中对myPtr的内容做任何事情(例如你正在检查它是否为null并且如果没有则分配),你应该丢失参数。