【问题标题】:void pointer as argument [duplicate]void指针作为参数[重复]
【发布时间】:2012-09-09 01:29:51
【问题描述】:

下面的C sn-p:

[...] 
void f1(void* a){
  printf("f(a) address = %p \n",a);
  a = (void*)(int*)malloc(sizeof(int));

  printf("a address = %p \n",a);
  *(int*)a = 3;

  printf("data = %d\n",*(int*)a);
}

void f(void){
  void* a1=NULL;
  printf("a1 address = %p \n",a1);

  f1(a1);

  printf("a1 address = %p \n",a1);
  printf("Data.a1 = %d\n",*(int*)a1);
}
[...]

结果

a1 address = (nil) 
f(a) address = (nil) 
a address = 0xb3f010 
data = 3
a1 address = (nil) 
Segmentation fault (core dumped)

a1为什么不在函数中保留已经分配给它的地址?

【问题讨论】:

标签: c pointers arguments argument-passing void-pointers


【解决方案1】:

由于这是 C,如果不传递指向指针的指针,就不能通过引用传递指针(例如,void ** 而不是 void * 指向指针)。您需要返回新指针。发生了什么:

f(a1);

将指针 (NULL) 的值作为a 的堆栈参数值推送。 a 获取该值,然后为自己重新分配一个新值(malloced 地址)。因为它是按值传递的,所以 a1 没有任何变化。

如果这是 C++,你可以通过引用传递指针来实现你想要的:

void f(void *&a);

【讨论】:

  • 在 C 中,您可以使用 void f(void **a) 来做到这一点。
  • @chris 好点。脑放屁时刻。
【解决方案2】:

将指向a1 的指针传递给您的函数,您不能更改a1 指向的位置。指针按值传递,因此在f1 中,您只更改a 持有的地址的副本。如果要更改指针,即为传入的指针分配新内存,则需要将指针传递给指针

void f1(void **a)
{
    // ...
    *a = malloc(sizeof(int));
    // ...

【讨论】:

    【解决方案3】:

    要通过函数调用更改变量,函数需要有关于参数的引用语义。 C没有原生的引用变量,但是可以通过取地址和传递指针的方式实现引用语义。

    一般:

    void mutate_thing(Thing * x)    // callee accepts pointer
    {
        *x = stuff;                 // callee derefences ("*")
    }
    
    int main()
    {
        Thing y;
        mutate_thing(&y);           // caller takes address-of ("&")
    }
    

    在您的情况下,Thingvoid *

    void f(void ** pv)
    {
        *pv = malloc(12);   // or whatever
    }
    
    int main()
    {
         void * a1;
         f(&a1);
    }
    

    【讨论】:

      【解决方案4】:

      基于 Kerrek SB 的示例,我用这个来演示 void 指针到指针作为参数以及如何使用它。

      #include <stdio.h>
      
      void test(void ** jeez)
      {
        *jeez = (void *) (int) 3;
      }
      
      
      int main (int argc, char* argv[])
      {
      void *a;
      test(&a);
      
      int b = *(int *)&a;
      printf("value returned = %d\n", b);
      
      return 0;
      }
      

      【讨论】:

        猜你喜欢
        • 2016-05-03
        • 1970-01-01
        • 1970-01-01
        • 2016-12-13
        • 2014-07-16
        • 2020-06-11
        • 2016-01-11
        • 1970-01-01
        • 2019-04-13
        相关资源
        最近更新 更多