【问题标题】:How to return 2D array in C with a function?如何使用函数在 C 中返回二维数组?
【发布时间】:2022-01-18 17:37:33
【问题描述】:

我在 C 中有两个二维数组。我们称它们为 a[row][col] 和 b[row][col]。我在数组 a 中生成了随机值。现在我想编写一个函数来计算值,返回二维数组,输出将分配给数组 b(这是一个生命的护航游戏)。

#include <stdio.h>
#include <stdlib.h>

int row, col = 0;

//creates row boundary
int create_row_line()
{
    printf("\n");
    for (int i = 0; i < col; i++)
    {
        printf(" -----");
    }
    printf("\n");
}

//returns the count of alive neighbours
int count_alive_neighbours(int a[row][col], int r, int c)
{
    int i, j, count = 0;
    for (i = r - 1; i <= r + 1; i++)
    {
        for (j = c - 1; j <= c + 1; j++)
        {
            if ((i < 0 || j < 0) || (i >= row || j >= col) || (i == r && j == c))
            {
                continue;
            }
            if (a[i][j] == 1)
            {
                count++;
            }
        }
    }
    return count;
}

int print_state(int x[row][col]){
    create_row_line();
    for (int i = 0; i < row; i++)
    {
        printf(":");
        for (int j = 0; j < col; j++)
        {
            printf("  %d  :", x[i][j]);
        }
        create_row_line();
    }
}

int count_values(int x[row][col]){
    int y[row][col];
    for (int i = 0; i < row; i++)
    {
        for (int j = 0; j < col; j++)
        {
            int neighbours_alive = count_alive_neighbours(x, i, j);
            // printf("%d" ,neighbours_alive);
            if ((x[i][j] == 0) && (neighbours_alive == 3))
            {
                y[i][j] = 1;
            }
            else if ((x[i][j] == 1) && (neighbours_alive == 3 || neighbours_alive == 2))
            {
                y[i][j] = 1;
            }
            else
            {
                y[i][j] = 0;
            }
        }
    }
    return y;
}

int main()
{
    //change row and column value to set the canvas size
    printf("Enter number of rows: ");
    scanf("%d", &row);
    printf("Enter number of cols: ");
    scanf("%d", &col);

    int a[row][col], b[row][col];
    int i, j, neighbours_alive;

    // generate matrix
    for (i = 0; i < row; i++)
    {
        for (j = 0; j < col; j++)
        {
            a[i][j] = rand() % 2;
        }
    }

    // print initial state
    printf("Initial state:");
    print_state(a);

    char quit;
    do {
        printf("Press enter to print next generation. To quit, enter 'q'.");
        scanf("%c", &quit);
        int** b = count_values(a);
        print_state(b);
        int** a = b;
    } while(quit != 'q');

    return 0;
} 

但是有一个错误。我是一个糟糕的 C 程序员,不知道应该怎么做才能获得理想的效果。将函数的输出分配给数组 b 后,我想分配 a=b 并从中循环以生成下一代。

所以问题是如何将 C 中的一个二维数组的值分配给另一个数组,以及如何从函数返回二维数组并将结果分配给现有的二维数组。感谢您的帮助

【问题讨论】:

  • 你写了“但是有一个错误。”。请edit您的问题并复制并粘贴错误消息。在复制所有值的意义上,分配整个数组是不可能的。 (除非数组是结构的成员。)
  • 更好的方法是保留两个二维数组,然后交换哪个是当前数组。
  • “如何在 C 中使用函数返回二维数组?”.. 一种选择是将指向数组的指针作为函数参数及其维度传递。该函数可以修改数组的内容,当返回其指针时,调用者可以访问更新的内容。另一个选择当然是将函数原型化为支持返回指向数组的指针的类型。数组对象本身不能传递,用C返回,只能是对象的指针。

标签: arrays c function


【解决方案1】:

数组是“不可修改的左值”,因此不能是赋值运算符的左参数。要复制数组,只需使用memcpy()。 例如:

int a[row][col], b[row][col];

memcpy(a, b, sizeof(int[row][col]));

返回数组是一个棘手的话题,尤其是在您使用可变长度数组时。 在thread 中讨论。

您必须以void* 的形式返回指向数组的指针,或者在二维数组的情况下,可以返回指向未定义大小数组的不完整类型的指针int(*)[]

此外,必须动态分配数组以将其生命周期延长到分配函数结束之后。记住在不再使用时释放内存。

void* count_values(int x[row][col]){
    int (*y)[col] = malloc(sizeof(int[row][col]));
    ...
    return y;
}

int main() {
  ...
  int (*b)[col] = count_values(a);
  ...
  free(b);
}

【讨论】:

    【解决方案2】:

    数组对象不能分配给函数、从函数返回或作为函数调用的参数传递。在后一种情况下,函数调用参数被转换为指向第一个元素的指针,并且声明为类型 T 的数组的函数参数被“调整”为指向类型 T 的指针(因此 void foo(int a[6]) 被调整为 void foo(int *a),例如)。

    由于main 已经有两个数组ab,您可以将它们都传递给count_values,将count_values 更改为接受两个数组,如下所示:

    void count_values(const int x[row][col], int y[row][col])
    {
        for (int i = 0; i < row; i++)
        {
            for (int j = 0; j < col; j++)
            {
                /* put next generation in y[i][j] here */
            }
        }
    }
    

    并从main 调用如下:

            count_values(a, b);
            print_state(b);
            memcpy(b, a, sizeof(a));
    

    (注意:memcpy#include &lt;string.h&gt; 声明。)

    除了每次都将a 复制到b 之外,您还可以拥有一个3-D 数组int a[2][row][col];,并为每一代翻转a[0]a[1] 的用法:

        int flip = 0;
        int a[2][row][col];
        int i, j, neighbours_alive;
    
        // generate matrix
        for (i = 0; i < row; i++)
        {
            for (j = 0; j < col; j++)
            {
                a[flip][i][j] = rand() % 2;
            }
        }
    
        // print initial state
        printf("Initial state:");
        print_state(a[flip]);
    
        char quit;
        do {
            printf("Press enter to print next generation. To quit, enter 'q'.");
            scanf("%c", &quit);
            // a[flip] contains the current generation,
            // a[1-flip] will contain the next generation.
            b = count_values(a[flip], a[1-flip]);
            // flip the usage of a[0] and a[1]
            flip = 1 - flip;
            // a[1-flip] now contains the previous generation
            // a[flip] now contains the new current generation
            print_state(a[flip]);
        } while(quit != 'q');
    

    一个可能的改进是将行数和列数作为函数参数传递,而不是使用全局变量:

    void create_row_line(int col)
    {
        /* print stuff */
    }
    
    int count_alive_neighbours(int row, int col, const int a[row][col], int r, int c)
    {
        int count = 0;
        /* count neighbours */
        return count;
    }
    
    void print_state(int row, int col, const int x[row][col])
    {
        /* print state */
    }
    
    void count_values(int row, int col, const int x[row][col], int y[row][col])
    {
        /* put next generation in y */
    }
    

    对应的函数调用:

        create_row_line(col);
    
        int neighbours_alive = count_alive_neighbours(row, col, x, i, j);
    
        print_state(row, col, a[flip]);
    
        count_values(row, col, a[flip], a[1-flip]);
    

    【讨论】:

      【解决方案3】:

      你提到的错误应该包括一些非致命的运行时错误,因为函数被定义为返回一个值,但没有返回语句......

      int create_row_line()
      {
          printf("\n");
          for (int i = 0; i < col; i++)
          {
              printf(" -----");
          }
          printf("\n");
          
          return 0;//added
      }  
      

      要么制作函数原型void create_row_line(),要么在底部添加return 语句。除了这些观察到的行为,并且在没有您在帖子中进一步解释的情况下,其他错误并不明显,所以我将笼统地解决标题问题......

      “如何用函数返回C语言中的二维数组”

      方法一: 此方法将说明如何创建和返回由函数分配的单个连续内存块组成的二维数组。

      //prtotype;
      void * arr_2d_alloc (size_t x, size_t y);//implemented
      void * arr_fill_2 (size_t x, size_t y, int array[x][y]);//implemented
      void arr_print_2 (size_t x, size_t y, int array[x][y]);//left to do
      
      int main(void)
      {
          int x=3, y=4;
      
          //Create 2D array, return from function
          int (*arr)[x] = arr_2d_alloc (x, y);
          if(arr)
          {    //pass 2D array in, return populated array out
               (*aptr_2)[y] = *(int *)arr_fill_2(x,y,aptr_2);//filling array
               //write routine output a 2D array, (see prototype above)
          }
          free(aptr_2); 
          
          return 0;
      }
      
      void * arr_2d_alloc (size_t x, size_t y)
      {
          int (*aptr_2)[x] = malloc( sizeof **aptr_2 ); // allocate a true 3D array
          if(aptr_2)
          {
              memset(aptr_2, 0, sizeof **aptr_2);//zero array
          }
          return aptr_2;
      }
      
      void * arr_fill_2 (size_t x, size_t y, int array[x][y])
      {
          for(size_t i=0; i<x; i++)
          {
              for(size_t j=0; j<y; j++)
              {
                  array[i][j] = 1+i*j;//some generic content
              }
          }
          return array;
      }
        
      

      方法二
      另一种方法是使用 VLA 排列将 VLA 数组作为参数传递。这将允许更改函数中的值,然后返回更新后的数组。下面是一个通用的例子来说明。

      注意数组大小的位置数组本身之前:

      void populate2D(int x, int y, int (*arr)[x][y]);
      
      int main(void)
      {
          int x=3, y=4;
          int arr[x][y];
          memset(arr, 0, sizeof arr);//initialize array
          populate2D(x, y, &arr);//passing array sizes, and pointer to array
          
          return 0;
      }
      
      void populate2D(int x, int y, int (*arr)[x][y])
      {
          for(int i=0;i<x;i++)
          {
              for(int j = 0;j<y;j++)
              {
                  (*arr)[i][j] = i*j;
              }
          }
      }
      

      如果两个数组的数组尺寸相同,例如在您的示例中,可以创建一个类似的原型来满足您的特定需求:

      void update_2D_arrays(int x, int y, int (*arr1)[x][y], int (*arr2)[x][y])
      {
           // Do work using arr1 and arr2 
      }
      

      【讨论】:

        【解决方案4】:

        一种简单但不高效的方法是您可以定义一个结构来保存二维数组。然后你可以简单地从函数中返回结构对象并相互分配。

        typedef struct {
            int array[row][col];
        } S2dArray;
        
        S2dArray count_values(S2dArray x){
           S2dArray y;
           ....
           return y;
        }
        
        int main() {
            S2dArray a, b;
            ....
            b = count_values(a);
            print_state(b);
            a = b;
            ....
        }
        

        【讨论】: