从函数中的 void * 参数返回数组

Returning a array from a void * argument in a function

提问人:csharp 提问时间:7/27/2021 最后编辑:Richard Chamberscsharp 更新时间:7/27/2021 访问量:256

问:

我有一个调变量函数,它至少接受 3 个参数,其形式为

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

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

如何返回数组?

函数定义是,第一个参数返回任意类型,具体取决于 调用的函数,是操作模式,并且是附加输入参数的数量,可以为零。里面有一个语句,它依赖于 ,可以调用一个或多个函数,并且可以返回任意类型的值。foo()modenum_paramsswitchfoo()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]);
}

我输入了对上下文和上下文的呼吁,它们起作用了。对于两个 int,但不返回任何内容,并且必须提供一个虚拟输出参数。因为没有给出输入值,但返回一个输出 int,它被强制转换为 star(int star),它工作并正确返回。bar1()bar2()bar1()bar2()

但是,对于内部,我生成了一个 10 元素数组作为测试,该数组从 print 语句中正确返回,但我无法将数组返回到 .我已经摆弄了各种涉及指针的语句,但是如果数组被初始化,要么返回一个零列表,或者如果没有初始化,则返回垃圾。bar3()foo()main()

如何正确返回数组?

C++ 隐式转换 按值传递

评论

7赞 Eric Postpischil 7/27/2021
这不是 C;C 没有运算符,如 中所示。你是用 C 还是 C++ 写作?newnew int[10];
0赞 kaylum 7/27/2021
更改为 并调用为 。还需要 (假设返回 .int xd[10];int *xd;foo(&xd, 3, 0)*(int*)ret_val = *p;*(int**)ret_val = p;bar3int *
0赞 Eric Postpischil 7/27/2021
在 中,您是要填充通过第一个参数传递给它的数组,还是希望它通过将指针放在 中来返回指向它已分配的数组的指针?foo(xd, 3, 0)fooxd
0赞 David Schwartz 7/27/2021
这个函数应该如何准确调用?应该指向什么?ret_val
0赞 Eric Postpischil 7/27/2021
@kaylum:这还不够。然后,他们将 an 作为 a 传递,但以 .int **void *fooint *

答:

0赞 Vlad from Moscow 7/27/2021 #1

在此电话会议中

foo(xd, 3, 0)

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

在函数中,此语句

*(int*)ret_val = *p;

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

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

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

a = b;

所以这个代码片段

      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();
0赞 Eric Postpischil 7/27/2021 #2

您可以按如下所示编写(在 C 中,因为这个问题最初是标记的)。注释显示了如何思考。请注意,接口已更改。fooret_valbar3

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

评论

0赞 Ted Lyngmo 7/27/2021
很抱歉弄乱了语言标签。OP 最初用 C 和 C++ 标记它,它不是 C。 多语言标记... :-/