Return VLA 和用法

Return VLA and usage

我有以下功能:

int* create_matrix_2(int rows, int cols)
{
    double (*A)[rows][cols] = malloc(sizeof(int[rows][cols]));

    for (int row = 0; row < rows; row++)
    {
        for (int col = 0; col < cols; col++)
        {
            *A[row][col] = row * cols + col;
        }
    }

    for (int row = 0; row < rows; row++)
    {
        for (int col = 0; col < cols; col++)
        {
            printf("%lf, " , *A[row][col]);
        }
        printf("\n");
    }
    return A;
}

我的问题是:如何 return 该函数的 VLA,类型是什么,如何将其写为函数签名以及如何在收到 return编辑数组?

目前我正在尝试这样做:

int (*matrix2)[height][width] = create_matrix_2(height, width);

for (int row = 0; row < height; row++)
{
    for (int col = 0; col < width; col++)
    {
        printf("%d" , (*matrix2)[row][col]);
    }
    printf("\n");
}

然后 运行:gcc 2d_array_test.c -o 2d_array_test.out -std=c99 -O0

但这会导致以下问题:

2d_array_test.c: In function ‘main’:
2d_array_test.c:35:34: warning: initialization from incompatible pointer type [enabled by default]
  int (*matrix2)[height][width] = create_matrix_2(height, width);
                                  ^
2d_array_test.c: In function ‘create_matrix_2’:
2d_array_test.c:105:2: warning: return from incompatible pointer type [enabled by default]
  return A;
  ^

编辑#1:

我尝试使用alk建议的代码,但是在编译时它给了我很多错误。这是一个单独的程序,其中包含您建议的代码和主要功能:http://pastebin.com/R6hKgvM0 我收到以下错误:

2d_array_test_new.c: In function ‘main’:
2d_array_test_new.c:18:2: warning: passing argument 3 of ‘create_matrix’ from incompatible pointer type [enabled by default]
  if (-1 == create_matrix(height, width, &matrix))
  ^
2d_array_test_new.c:10:5: note: expected ‘int **’ but argument is of type ‘int (**)[(sizetype)(height)][(sizetype)(width)]’
 int create_matrix(size_t, size_t, int**);
     ^
2d_array_test_new.c: At top level:
2d_array_test_new.c:37:5: error: conflicting types for ‘create_matrix’
 int create_matrix(size_t rows, size_t cols, int(**a)[rows][cols])
     ^
2d_array_test_new.c:10:5: note: previous declaration of ‘create_matrix’ was here
 int create_matrix(size_t, size_t, int**);
     ^
2d_array_test_new.c: In function ‘create_matrix’:
2d_array_test_new.c:45:11: error: ‘EINVAL’ undeclared (first use in this function)
   errno = EINVAL;
           ^
2d_array_test_new.c:45:11: note: each undeclared identifier is reported only once for each function it appears in
2d_array_test_new.c:40:6: warning: variable ‘errno’ set but not used [-Wunused-but-set-variable]
  int errno;
      ^

错误似乎主要与 return 类型有关。如何正确写入该数组的类型?

  • 参考 1st 警告:

    warning: initialization from incompatible pointer type
    

    这里

    int (*matrix2)[height][width] = create_matrix_2(height, width);
    

    int (*matrix2)[height][width]int * 根本不一样。

  • 参考第 2 警告:

    warning: return from incompatible pointer type 
    

    这归功于定义

    double (*A)[rows][cols] = malloc(sizeof(int[rows][cols]));
    

    int * create_matrix_2() 返回 A 时。

    int *double (*A)[rows][cols] 也不一样。

我建议你把函数改成这样:

#include <errno.h> /* for errno and EINVAL */
#include <stdlib.h> /* for malloc() */


int create_matrix_2(size_t rows, size_t cols, int(**a)[rows][cols])
{
  int result = 0;

  if (NULL == a)
  {
    result = -1;
    errno = EINVAL;
  }
  else
  {
    (*a) = malloc(sizeof **a);
    if (NULL == (*a))
    {
      result = -1;
    }
    else
    {
      for (size_t row = 0; row < rows; row++)
      {
        for (size_t col = 0; col < cols; col++)
        {
          (**a)[row][col] = row * cols + col;
        }
      }

      for (size_t row = 0; row < rows; row++)
      {
        for (size_t col = 0; col < cols; col++)
        {
          printf("%d, " , (**a)[row][col]);
        }

        printf("\n");
      }
    }
  }

  return result;
}

并这样称呼它:

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


int create_matrix_2(size_t rows, size_t cols, int(**a)[rows][cols]);


int main(void)
{
  int result = EXIT_SUCCESS;

  int (*matrix2)[height][width] = NULL;
  if (-1 == create_matrix_2(height, width, &matrix2))
  {
    perror("create_matrix_2() failed");
    result = EXIT_FAILURE;
  }
  else
  {
    for (size_t row = 0; row < height; row++)
    {
      for (size_t col = 0; col < width; col++)
      {
        printf("%d, " , (*matrix2)[row][col]);
      }

      printf("\n");
    }

    free(matrix2);
  }

  return result;
}

样本

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

void * create_matrix_2(int rows, int cols){
    int (*A)[rows][cols] = malloc(sizeof(int[rows][cols]));

    for (int row = 0; row < rows; row++){
        for (int col = 0; col < cols; col++){
            (*A)[row][col] = row * cols + col;
        }
    }

    for (int row = 0; row < rows; row++){
        for (int col = 0; col < cols; col++){
            printf("%d, " , (*A)[row][col]);
        }
        printf("\n");
    }
    return A;
}

int main(void){
    int width = 5, height = 3;
    int (*matrix2)[height][width] = create_matrix_2(height, width);

    for (int row = 0; row < height; row++){
        for (int col = 0; col < width; col++){
            printf("%d " , (*matrix2)[row][col]);
        }
        printf("\n");
    }
    free(matrix2);
    return 0;
}

简短的回答是你不能。

问题是从函数 return 编辑的类型必须在编译时固定,不能依赖于其参数的数值(在 运行 时提供)。

但是,您可以将 create_matrix2() 更改为 return 空指针。这利用了这样一个事实,即在 C 中,(几乎)任何指针都可以隐式转换为 void 指针,反之亦然。

   void *create_matrix2(int rows, int columns)
   {
       /* as you've implemented it, except that A should be int not double */
   }

   int main()
   {
        int rows = 2, cols = 3;
        int (*m)[rows][cols] = create_matrix2(rows, cols);

         /*  use *m as a pointer to an array with 2 rows and 3 cols */
   }

然后它会提供您所寻求的幻觉

这样做的危险 - 以及我刚才使用 "illusion" 这个词的原因 - 是与 void 指针的转换会阻止编译器进行类型检查。所以这将通过编译器,但会由于从数组末尾掉落而导致未定义的行为。

   int main()
   {
        int rows = 2, cols = 3;
        int (*m)[rows][cols] = create_matrix2(rows-1, cols-1);   /*  whoops - deliberate typos here */

         /*  use *m as a pointer to an array with 2 rows and 3 cols */
   }

因为这有效地告诉编译器将动态分配的数组视为具有比函数中实际分配的更多的行和列。

首先,您的代码存在一些问题。你有一个指向二维整数数组的双数组指针,这没有任何意义。

此外,由于 A 是指向二维数组的指针,因此您不能执行 *A[row][col]。因为[]的优先级高于*,所以代码等价于*(A[row][col])。 turn 表示 "give me row number of 2D matrices, then..."。代码最终会越界。

声明指向动态分配的多维数组的数组指针时的技巧是省略最内层的维度。这样您就可以像使用常规多维数组一样使用语法。

double (*A)[cols] = malloc(sizeof(double[rows][cols]));
...
A[x][y] = ...;

A[x][y] 则表示 "In my array A, where each item is an array of size cols, access array number x and then index y in that array".


至于如何 return 这种类型的数组的问题......你不能,因为函数声明必须包含数组指针的维度。它必须是这样的怪物:

double (*create_matrix_2(int rows, int cols))[rows][cols]   // wont compile

如果我们忽略 returning 数组指针(和函数指针)的 C 语法完全是 FUBAR,则上述 C 语法无效。因为行和列必须在编译时知道时间。

解决上述问题并同时修复问题的解决方案是return通过参数return数组指针:

void create_matrix_2 (int rows, int cols, double(**array)[rows][cols])
{
    // omit inner-most dimension to get sane syntax:
    double (*A)[cols] = malloc(sizeof(double[rows][cols]));

    for (int row = 0; row < rows; row++)
    {
        for (int col = 0; col < cols; col++)
        {
            A[row][col] = row * cols + col;
        }
    }

    for (int row = 0; row < rows; row++)
    {
        for (int col = 0; col < cols; col++)
        {
            printf("%lf, " , A[row][col]);
        }
        printf("\n");
    }

    // "brute" pointer conversion but doesn't break aliasing:
    *array = (void*)A;
}