【问题标题】:How to return 2 1D arrays from function to main in C如何在C中将2个一维数组从函数返回到main
【发布时间】:2021-09-21 11:25:05
【问题描述】:
#include <stdio.h>
int *func()
{
   int *a=malloc(5);
   int *b=malloc(5);
   for(int i=0;i<5;i++)
   {
     a[i]=i+1;
     b[i]=i+5;
   }
   int *l= malloc(2);
   l[0]=a;
   l[1]=b;
   //printf("%p %p ",l[0],l[1]);
   return l;
} 
int main() 
{ 
  int *k=func();
} 

对于上述代码,如何将 a,b 数组返回给 main 函数? 在为两个数组 a 和 b 赋值后,我将它们的地址分配给了新数组 l。现在将l返回给main后,如何在main函数中同时指定数组a和b的值?

【问题讨论】:

  • 您使用返回值的方式肯定令人惊讶(如果函数 [would] 返回两个数组,则无法正常工作)。
  • 你不能。在 C 中,您可以(最多)返回 one 值。这不能是一个数组。有各种变通方法,但答案是无法完成。
  • 我不明白您为什么在您接受答案后对问题做出重大改变 - 为什么?
  • 一般来说malloc和free应该在同一个层次上做,最好是同一个函数。在 main 中创建数组并将它们传递给 func 进行填充。

标签: arrays c return return-type function-definition


【解决方案1】:

C 中的函数只能返回单个事物 - 该事物可以是具有多个属性的 struct,但您不能像在 Python 或 Perl 中那样返回和分配多个独立项。

如果调用者需要函数中的多个独立项,那么您将需要使用多个输出参数 - 调用者必须传递指向它希望函数更新的事物的指针,并且函数会更新指向的事物:

bool f( T *a, T *b )          // for some arbitrary type T
{
  /**
   * The *expressions* *a and *b have type T; writing to *a 
   * and *b in f is equivalent to writing to x and y in main.  
   */
  *a = new_T_value();         // writes a new value to the thing a points to
  *b = another_new_T_value(); // writes a new value to the thing b points to
  return some_boolean_value();
}

int main( void )
{
  T x, y;             // for some arbitrary type T
  if ( f( &x, &y ) )  // f will write new values to x and y
    do_something();
  ...
}

我们可以将T 替换为指针类型P *,这给了我们:

bool f( P **a, P **b )            // for some arbitrary type P
{
  /**
   * The expressions *a and *b have type P *; writing to *a and *b
   * in f is equivalent to writing to x and y in main.
   */
  *a = new_Pstar_value();         // writes a new value to the thing a points to
  *b = another_new_Pstar_value(); // writes a new value to the thing b points to
  return some_boolean_value();
}

int main( void )
{
  P *x, *y;             // for some arbitrary type T
  if ( f( &x, &y ) )    // f will write new values to x and y
    do_something();
  ...
}

语义完全相同——我们希望函数fxy 写入新值,因此我们必须将指向xy 的指针作为参数传递。只是在这种情况下 xy 已经有一个指针类型(P *),所以我们最终将指针传递给指针(P **)。

这是最直接的方法,需要对现有代码进行最少的更改:

#include <stdio.h>
#include <stdlib.h> // need this for malloc

/**
 * We want func to dynamically allocate arrays of int and
 * assign the resulting pointers to *a and *b.  We also want
 * to dynamically allocate and return an array of int *.
 */
int **func( int **a, int **b)
{
   /**
    * malloc(5) allocates 5 *bytes*, not 5 ints.
    * We need to multiply the number of things we 
    * want by the size of each thing.  
    */
   *a=malloc(5 * sizeof **a); // sizeof **a == sizeof (int)
   *b=malloc(5 * sizeof **b);

   for(int i=0;i<5;i++)
   {
     /**
      * The postfix [] operator has higher precedence than the
      * unary * operator; we don't want to dereference a[i] and 
      * b[i], we want to index into what a and b *point to*, so
      * we must explicitly group the * operator with the variable
      * name. 
      */
     (*a)[i]=i+1; 
     (*b)[i]=i+5;  
   }
   /**
    * Each l[i] holds a value of type int *,
    * so l needs to have type int **
    */
   int **l= malloc(2 * sizeof *l);
   l[0]=*a;
   l[1]=*b;
   //printf("%p %p ",l[0],l[1]);
   return l;
} 

int main( void ) 
{ 
  int *a, *b;
  int **k=func( &a, &b );
} 

【讨论】:

    【解决方案2】:
    void func(int **aa, int **bb)
    {
        static int a[5]={1,2,3,4,5};
        static int b[5]={1,2,3,4,5};
    
        *aa = a;
        *bb = b;
    }
    
    void func2(int **aa, int **bb)
    {
        int *a = malloc(5 * sizeof(*a)); 
        int *b = malloc(5 * sizeof(*b)); 
        
        memcpy(a, (int []){1,2,3,4,5}, 5 *sizeof(*a));
        memcpy(b, (int []){1,2,3,4,5}, 5 *sizeof(*b));
    
        *aa = a;
        *bb = b;
    }
    
    
    typedef struct
    {
        int a[5];
        int b[5];
    
    }mydata;
    
    mydata func1(void)
    {
        mydata d = { .a = {1,2,3,4,5}, .b = {1,2,3,4,5}};
        
        /*  ... */
        return d;
    }
    

    第二种方法非常昂贵,因为整个结构被复制通过(在大多数实现中)堆栈。

    示例用法:

    int main(void)
    {
        int *a,*b;
    
        func2(&a, &b);
    
        for(size_t i = 0; i < 5; i++)
        {
            printf("a[%zu] = %d, b[%zu]=%d\n", i, a[i], i, b[i]);
        }
    }
    

    【讨论】:

    • #include int *func() { int *a=malloc(5); int *b=malloc(5); for(int i=0;i
    • int *a=malloc(5) ir 错了!!!您只分配 5 个字节而不是 5 个整数。在我的回答中查看如何完成
    • 是的,初始化后我使用 for 循环将 1 到 5 个值附加到动态数组
    • 您不能将值“附加”到数组中。
    • 我的意思是我已经使用 for 循环赋值了
    【解决方案3】:

    你可以这样做

    struct Array
    {
        int a[5];
        int b[5];
    };
    
    struct Array func( void )
    {
        struct Array a = 
        { 
            {1,2,3,4,5},
            {1,2,3,4,5}
        };
    
        return a;
    }
    
    int main( void )
    {
       struct Array a = func();
       //...
    } 
    

    另一种方法是动态分配数组,并通过输出参数从函数返回指向分配数组的指针。例如

    #include <stdio.h>
    #include <stdlib.h>
    
    void func( int **a, size_t *n1, int **b, size_t *n2 )
    {
        *n1 = 5;
        *a = malloc( sizeof( int ) * *n1 );
        
        if ( *a != NULL )
        {
            int value = 1;
            for ( size_t i = 0; i < *n1; i++ )
            {
                ( *a )[i] = value++;
            }
        }
        
        *n2 = 5;
        *b = malloc( sizeof( int ) * *n2 );
        
        if ( *b != NULL )
        {
            int value = 1;
            for ( size_t i = 0; i < *n2; i++ )
            {
                ( *b )[i] = value++;
            }
        }
    }
    
    int main(void) 
    {
        int *a = NULL;
        int *b = NULL;
        size_t n1 = 0;
        size_t n2 = 0;
        
        func( &a, &n1, &b, &n2 );
        
        //...
    
        free( a );
        free( b );
        
        return 0;
    }
    

    【讨论】:

    • 我们可以不使用结构和传递2个数组的地址吗?
    • @Anonymous Arrays 没有赋值运算符,并且您可能不会从函数返回指向具有自动存储持续时间的本地数组的指针,因为退出函数后它将不再存在。
    • 是的,可以通过在函数中动态声明数组并将它们的地址合并到另一个数组中并在主函数中打印数组来实现吗?
    • #include int *func() { int *a=malloc(5); int *b=malloc(5); for(int i=0;i
    • @Anonymous 您可以动态分配数组。请参阅我的附加答案。
    猜你喜欢
    • 2014-06-20
    • 2020-09-19
    • 2017-02-26
    • 1970-01-01
    • 1970-01-01
    • 2014-12-19
    • 1970-01-01
    • 2020-04-08
    • 2011-07-09
    相关资源
    最近更新 更多