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);