C++ 如何更改C+;中的指针参数内容+;
给定函数声明:C++ 如何更改C+;中的指针参数内容+;,c++,pointers,C++,Pointers,给定函数声明: void foo(void *ptr); 我无法更改函数的签名。 现在我需要在foo中分配内存,从ptr开始。 如果我写: void foo(void *ptr) { ptr = malloc(NUM * sizeof(TYPE)); } 当我使用以下命令调用指针时,它实际上不会更改指针的内容: void *myPtr = NULL; foo(myPtr); 我知道原因,因为我正在将myPtr的副本传递到foo() 我需要做的是将输入参数声明为指针的引用: foo(vo
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++中这样做。我必须在这个函数之外分配内存 如果您可以在不更改签名的情况下将代码移动到
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...
}
这样,调用原始函数的任何代码都仍然可以工作,需要检索指针的新代码可以使用trap\u foo()
来实现这一点
你可以用另一个。它更快/更紧凑,但它会破坏依赖于现有API的任何现有代码
void foo(void *trap_ptr)
{
void **ptr = (void**)trap_ptr;
*ptr = malloc(NUM * sizeof(TYPE));
// Et cetera...
}
然后
#include "foo_header.h"
int main()
{
void *some_pointer;
trap_malloc_set(&some_pointer):
foo(some_pointer);
trap_malloc_unset();
return 0;
}
void hacky_foo(void **ptr)
{
foo((void*)ptr);
}
int main()
{
void *the_pointer;
hacky_foo(&the_pointer);
return 0;
}
如果不更改函数签名或调用站点,则不可能实现您想要的功能。i、 e.一个非常肮脏的黑客行为是:
void foo(void *ptr) {
*((void **)ptr) = malloc(NUM * sizeof(TYPE));
}
int main() {
void *myPtr = NULL;
foo(&myPtr);
}
然而,在大多数情况下(特别是,如果您不想更改现有的调用站点),如果您编写一个新函数来实现您想要的功能,并将foo
作为它的包装器(反之亦然,具体取决于foo之前应该做什么),您可能会过得更好:
void new\u foo(void*&ptr){
//…以前在原版foo中出现的东西
ptr=malloc(NUM*sizeof(TYPE));
//…不管最初的foo里发生了什么
}
无效的FO(Valu**PTR){//< p>您应该真正地将这个标记作为C问题——这种空洞*指针愚蠢在C++中被禁止。虽然它是语言的一部分,并且偶尔也有它的用途,但你可能更幸运地从需要寻找C问题的人那里得到你所需要的专业知识。
继续问你的问题,我认为你想做什么(至少你正在发布的例子)根本是不可能的——具体来说:
void *myPtr = NULL;
foo(myPtr);
考虑一下您在这里实际执行的操作。您正在声明一个带有void*类型的变量myPtr,并为其分配一个占位符值——一个无效的内存区域,C程序员调用NULL,它通常为0(C++程序员更喜欢nullptr,它是一种特定类型,提供了一些安全好处)
现在将其传递给foo:
void foo(void *ptr) {
ptr = malloc(NUM * sizeof(TYPE));
}
foo收到一个空指针——一个无效的内存地址,通常为0。当调用ptr=malloc(…)
语句时,变量ptr
获取malloc返回的内存地址的值,malloc为您分配了一些内存并返回指向该内存的地址
您尚未修改变量myPtr的内容,该变量包含无效的内存地址NULL
您需要更改函数的签名,以便它可以使用有效地址(即您刚才分配的内存地址)填充myPtr。您可以使用以下方法完成此操作:
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.
我看不出有任何其他的解决办法。顺便说一句,我更喜欢选项1,因为在阅读时,最清楚的是发生了什么:
myPtr = foo(myPtr);
除非您正在对foo中的myPtr的内容进行任何处理(例如,您正在检查它是否为null,如果不是,则进行分配)你可以丢失一个指针。< /p>你能返回一个指针吗?除非你能改变返回类型,否则你就无能为力。BTW是C++,不是C/C++。@ kfsOne——你到底是怎么建议的,不改变函数sig?@ PrimeFixC没有引用。你可以通过指针的地址而不是点吗?呃作为一个论点?你不必为此更改签名。你可以这样做,而不必触碰这两个签名中的任何一个(见我的答案)。@KerryLand据我所知,你更改了呼叫站点(你现在呼叫的是trap_foo而不是foo)这只是一种方便。如果你读了我的答案,你会发现事实并非如此。你调用同一个函数,但用陷阱挂钩将调用包围起来。trap\u foo
只是把它变成了一个助手函数。@KerryLAnd:你仍然需要调用某个函数(无论是foo_trap
还是trap_malloc_set
,地址为'myPtr'(some_ptr
)作为一个参数。事实上,你必须明确地调用helper函数,这意味着你必须控制调用站点。不,这意味着你必须控制那些需要它的调用站点。我的意思是,你不必更改“调用语法”,正如您所说。当且仅当您的代码需要检索指针时,您才调用包装函数。您的答案将使依赖旧接口的任何旧代码崩溃,因此所有代码都必须更改。我的代码没有此类要求。如果OP无法更改签名,很可能是因为该函数已被使用相当重要,但现在需要新代码使用,但仅仅为此更改旧代码可能是不可行的涉及调用不同的函数。最好根本不使用foo
,并消除所有的复杂性。你能解释一下,是什么让第一个版本比第二个版本更不黑客吗?@juanchopanza:仔细阅读代码。你实际上不需要调用不同的函数,而是用陷阱h围绕代码调用foo
ooks.@MikeMB:没什么特别的,但第一个版本允许旧代码按它的方式工作,而“新”代码(无论是新的还是不新的)需要检索指针的值来获取指针,使用它们两个相同的底层函数。本质上,您的代码所说的是“fo”
myPtr = foo(myPtr);