【问题标题】:Returning a array from a void * argument in a function从函数中的 void * 参数返回数组
【发布时间】:2021-10-02 18:30:05
【问题描述】:

我有一个可变参数函数,它至少需要 3 个参数,格式为

foo(void* ret_val, int mode, int num_params, ...)

可变参数函数foo() 的一般用途可能涉及返回不同的数据类型以及可以具有各种数据类型的任意数量的输入参数,但我无法找到返回数组的方法。

如何返回数组?

函数定义是第一个参数根据foo()调用的函数返回任意类型,mode是操作方式,num_params是附加输入参数个数,可以为零.在foo() 中有一个switch 语句,它依赖于mode,可以调用一个或多个函数,并且可以返回任意类型的值。

作为一个简化的示例,假设我有以下 3 个由foo() 调用的函数:

void bar1(int i, int, j) {
// Do some calculations but return nothing.
}

int bar2() {
// Do some calculations and return a value.
}

int* bar(3) {
// Do some calculations with an array and return it.
}

那么在foo()我可以有以下代码:

foo(void* ret_val, int mode, int num_params, ...) {
  va_list args;
  va_start(args, num_params);
  switch (mode) {
  case 1: {
          int a = va_arg(args, int);
          int b = va_arg(args, int);
          bar1(a, b);
          }
          break;
  case 2: {
          int val = bar1();
          *(int*)ret_val = val;
          }
          break;
  case 3: {
          int* p = new int[10];
          p = bar3();
          // Add a loop to test out that the array has been read from bar3(), which works.
          *(int*)ret_val = *p; // <== This is where the problem is.
          }
          break;
      }
      va_end(args);
}
        

然后在主程序中我可以通过以下方式调用foo()

int x;
foo(&x, 1, 2, 10, 20); // Call bar1()

foo(&x, 2, 0);         // Call bar2()
printf("%d\n", x);

int xd[10];            // Declare and initialize xd.
for (int i = 0; i < 10; i++) {
    xd[i] = 0;
}
foo(xd, 3, 0)          // Call bar3()
for (int i = 0; i < 10; i++) {
    printf("%d %d\n", i, xd[i]);
}

我调用了bar1()bar2() 以获取上下文,并且它们起作用了。对于bar1(),提供了两个整数,但没有返回任何内容,并且必须提供一个虚拟输出参数。对于bar2(),没有给出输入值,但返回了一个输出int,它被转换为star(int star),它可以正常工作并正确返回。

但是,对于bar3(),我在内部生成了一个包含 10 个元素的数组作为测试,该数组在 print 语句中的foo() 中正确返回,但我无法将数组返回给main()。我摆弄了各种涉及指针的语句,但是如果数组已初始化,则返回零列表,否则返回垃圾。

如何正确返回数组?

【问题讨论】:

  • 这不是C; C 没有 new 运算符,如 new int[10];。你是用 C 还是 C++ 编写的?
  • int xd[10]; 更改为int *xd; 并调用为foo(&amp;xd, 3, 0)。还需要*(int*)ret_val = *p;*(int**)ret_val = p;(假设bar3 返回int *
  • foo(xd, 3, 0) 中,您希望foo 填充一个通过第一个参数传递给它的数组,还是希望它返回一个指向它已分配的数组的指针通过将指向该数组第一个元素的指针放在xd?
  • 这个函数应该如何被准确调用? ret_val 应该指向什么?
  • @kaylum:这还不够。然后他们将int ** 作为void * 传递,但在foo 作为int * 访问它。

标签: c++ implicit-conversion pass-by-value


【解决方案1】:

在本次通话中

foo(xd, 3, 0)

数组指示符xd 被转换为指向其第一个元素的指针,并且该函数处理该值的副本。

函数内this语句

*(int*)ret_val = *p;

只需将数组xd的第一个元素更改为指针p指向的数组第一个元素的值。

数组没有复制赋值运算符。例如,您不能将一个数组分配给另一个数组

int a[10] = { /*...*/ };
int b[10] = { /*...*/ };

a = b;

所以这段代码sn-p

      int* p = new int[10];
      p = bar3();
      // Add a loop to test out that the array has been read from bar3(), which works.
      *(int*)ret_val = *p;

没有意义。此外,似乎存在内存泄漏,因为最初为指针p 分配了已分配内存的地址

  int* p = new int[10];

然后用函数bar3返回的值重新赋值。

  p = bar3();

【讨论】:

    【解决方案2】:

    您可以编写foo,如下所示(在 C 中,因为这个问题最初是被标记的)。评论展示了如何看待ret_val。请注意,bar3 的接口已更改。

    /*  ret_val is a pointer to some type T, a "T *", that has been converted to
        "void *".  To use it, we convert it back to its original type "T *".
    */
    foo(void *ret_val, int mode, int num_params, ...)
    {
        va_list args;
        va_start(args, num_params);
    
        switch (mode)
        {
            case 1:
            {
                //  T is void.  Nothing is returned via ret_val.
                int a = va_arg(args, int);
                int b = va_arg(args, int);
                bar1(a, b);
            }
            break;
    
            case 2:
            {
                /*  We will return an int, so T is an int, and we convert ret_val
                    back to "int *".
                */
                int val = bar1();
    
                //  Return val.
                * (int *) ret_val = val;
            }
            break;
    
            case 3:
            {
                /*  We will return a pointer to an int, so T is an "int *", and
                    we convert ret_val back to "int **".
                int *p = malloc(10 * sizeof p);
                if (!p)
                {
                    fprintf(stderr, "Error, memory allocation failed.\n");
                    exit(EXIT_FAILURE);
                }
    
                bar3(p);
    
                //  Return p.
                * (int **) ret_val = p;
            }
            break;
        }
    
        va_end(args);
    }
    

    然后,对于案例 3,您可以拨打 foo

    int *xd;
    foo(&xd, 3, 0);
    

    【讨论】:

    • 很抱歉弄乱了语言标签。 OP 最初用 C 和 C++ 标记它,而不是 C。多语言标记... :-/
    猜你喜欢
    • 2016-08-28
    • 2017-07-13
    • 1970-01-01
    • 2015-01-24
    • 2019-10-08
    • 2020-12-08
    • 2023-01-28
    • 2011-03-26
    • 1970-01-01
    相关资源
    最近更新 更多