繁体   English   中英

你可以将多维数组作为指针传递给C函数,然后将它们转换回函数内的数组吗?

[英]Can you pass multi-dimensional arrays into a C function as pointers and then cast them back into arrays inside the function?

问题:假设您正在尝试在C中编写一个函数,该函数将使用文件中的值填充2D数组。 该文件包含按行(记录)排列的值,其中每行包含许多字段。 该函数应该接收指向2D数组的指针和文件的地址并填充数组。 重要的是,该功能应独立于每条记录有多少字段。 例如,在一个程序中,您可以调用该函数从文件读取值,其中每个记录有四个字段:

int array_of_values[MAX_NUMBER_OF_RECORDS][4];
fill_in_array(array_of_values, "spacetime.csv");

在另一个程序中,您可能希望在每个记录有11个字段时填写值:

int array_of_values[MAX_NUMBER_OF_RECORDS][11];
fill_in_array(array_of_values, "M-theory.csv");

不幸的是,如果你试图这样做,你会违反C处理多维数组的方式。 多维数组在C中不是作为指向数组的指针数组实现的,而是作为一个长的一维数组实现的。 这意味着函数需要知道数组的宽度才能从中读取数据。

所以下面的函数定义会给你一个错误:

void fill_in_array(int array_of_values[MAX_NUMBER_OF_RECORDS][], char *path)

[请注意,以下情况可以:

void fill_in_array(int array_of_values[][MAX_NUMBER_OF_RECORDS], char *path)

因为编译器不需要知道第一个维度的索引,但是假设这是不允许的(例如,如果函数需要使用像array_of_values[1]这样的单个记录)。

这是我在程序中达到的要点。 有两种解决方案可供选择:

  1. 强制该函数使用固定数量的字段。 我显然不会这样做,但我可以,例如,声明一个常量MAX_NUMBER_OF_FIELDS并将未使用的字段留空。
  2. 使fill_in_array函数接受指针而不是数组,并动态分配包含字段的Iliffe向量。 这是一个很有吸引力的想法(因为它会阻止我们声明最大数量的记录/字段,但这也意味着我们必须创建(并记住使用!)一个函数来释放字段数组。

我有另外一个想法。 那就是将函数的声明修改为以下内容:

void fill_in_array(int **array_of_values, int number_of_fields, char *path)

(这里, number_of_fields指的是每条记录的字段数,因此我们可以将其称为fill_in_array(array_of_values, 4, "spacetime.csv");

请注意,参数array_of_values不再是显式数组,而是指针。 通常,如果指定双指针指向2D数组,则结果毫无意义。 我的想法是可以使用number_of_fields参数,以便函数知道如何处理像array_of_values[i][j]这样的表达式。

原则上这应该是相当容易的:实际上,如果a是2D数组,那么a[i][j]被定义为

*(a + (i * n) + j)

其中n是数组的长度,所以我们可以用*(array_of_values + (i * number_of_fields) + j)替换每个出现的array_of_values[i][j] ,并且每次出现的array_of_values[i]array_of_values + (i * number_of_fields) 但是,这段代码很难阅读。 有没有办法告诉编译器数组的宽度是number_of_fields以便我可以使用索引表示法来访问数组的元素?

不,没有这样的方式。

一旦需要进行通用地址计算,就需要自己实现。

祝贺您获得添加显式参数的解决方案,该参数描述了每条记录的字段数,这当然是应该如何完成的。

您可以使用函数内部的宏来使地址计算更容易管理。

有一些解决方案。

使用结构:

typedef struct {
  // whatever appears in a record
} record_t

void fill_in_array(record_t records[MAX_NUMBER_OF_RECORDS], const char* path);

请注意,这只有在编译时知道记录的大小才有意义,在给出您的示例时,它可能不是。

使用步幅:

void fill_in_array(int *array_of_values, int stride, const char *path)
{
  #define IDX(x, y) (x + (y * stride))

  // get the val at i,j
  int val = array_of_values[IDX(i,j)];

  #undef IDX
}

您已经在函数中使用number_of_fields建议了这种方法,这是一个步幅,但是大步是一个术语,其他开发人员在查看您的代码时更容易识别。

一个小的无关点,如果你不改变path的内容,你应该使它成为const :)

我相信你在C ++中看到的是什么,但在C中却没有。 在C ++中,您可以定义模板函数,以便在编译时使用大小数组,编译器负责其余部分。 在C中,有两种方法:

  • 明确定义大小
    这是memcpy等函数的情况,您可以在其中指定元素的数量

     void process_array(int *data[], size_t max_x, size_t max_y) .... 
  • 使用无效数字定义大小
    这是像strlen这样的函数的情况,其中数据以某个值终止(此处为'\\0'
    因此,如果您想要一个具有矩阵但可变数量的元素的函数,则必须定义一种如何在数据中指示的方法。

     #define ARRAY_TERM -1 void process_array(int *data[]) { size_t i, j; for (i = 0; data[i]; i++) { for (j = 0; data[i][j] != ARRAY_TERM; j++) { ... } } } ... 

希望你有这个想法。 使用起来不太方便。

还有另一种方法:定义自己的类型。 是的,在许多情况下,这是一个可行的选择:

typedef struct array *array_t;
struct array
{
    size_t max_x, max_y;
    int *data;
};

使用它的基本功能集:

int array_init(array_t *a; size_t max_x, size_t max_y)
{
    array_t res;
    res = malloc(sizeof(*res));
    res->max_x = max_x;
    res->max_y = max_y;
    res->data = calloc(max_x * max_y, sizeof(int));
    *a = res;
    return 0;
}

void array_destroy(array_t *a)
{
    free((*a)->data);
    free(*a);
}

然后,您可以定义附加功能以进行操作。

除非您仅限于C89(即MSVC编译器),否则您可以像这样传递多维数组:

#include <stdio.h>

void fill_in_array(size_t m, size_t n, int array_of_values[m][n])
{
  for (size_t i = 0; i < m; ++i) {
    for (size_t j = 0; j < n; ++j) {
      array_of_values[i][j] = ((i == j) ? 1 : 0);
    }
  }
}

void print_array(size_t m, size_t n, int array_of_values[m][n])
{
  for (size_t i = 0; i < m; ++i) {
    for (size_t j = 0; j < n; ++j) {
      printf(" %d", array_of_values[i][j]);
    }
    printf("\n");
  }
}

int main()
{
  {
    int array_of_values[2][4];
    fill_in_array(2, 4, array_of_values);
    print_array(2, 4, array_of_values);
  }
  {
    size_t h = 6, w = 5;
    int array_of_values[h][w];
    fill_in_array(h, w, array_of_values);
    print_array(h, w, array_of_values);
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM