【问题标题】:Passing an array of arrays in C在 C 中传递数组数组
【发布时间】:2010-12-24 21:08:08
【问题描述】:

我需要一个函数,它接受一个二维数组并生成随机位,所以结果是一个随机二进制字符串数组。

我有以下代码,

#define pop_size 50
#define chrom_length 50
main() {
    int population[pop_size][chrom_length];
    init_pop(&population);
}
int init_pop(int *population[][]) {
    for(i = 0; i < pop_size; i++) {
        for(j = 0; j < chrom_length; j++) {
            *population[i][j] = rand() % 2;
        }
    }
    return 0;
}

在编译时,我收到以下错误消息:

数组类型的元素类型不完整

有什么建议吗?

【问题讨论】:

  • 通常将#defines 写成大写,以便将它们与常规变量区分开来。我认识一个人,他以前用小写写#defines,直到他花了一整天的时间寻找一个错误,因为#define 和一个变量命名相同。

标签: c pointers


【解决方案1】:

是时候进行常规的演讲了...

当数组表达式出现在大多数上下文中时,它的类型会隐式地从“T 的 N 元素数组”转换为“指向 T 的指针”,并将其值设置为指向数组的第一个元素。此规则的例外情况是数组表达式是 sizeof 或一元 &amp; 运算符的操作数,或者它是在声明中用作初始值设定项的字符串文字。

在您的代码上下文中,这一切意味着什么?

表达式population 的类型是“pop_size-element array of chrome_length-element arrays of int”。按照上面的规则,在大多数情况下,表达式population 将隐式转换为类型“指向chrome_length-int 元素数组的指针”或int (*)[chrome_length]

然而,表达式&amp;population 的类型是“指向pop_size-元素数组chrome_length-int 元素数组的指针”或int (*)[pop_length][chrome_size],因为population 是一元的操作数&amp; 运营商。

请注意,这两个表达式具有相同的(数组第一个元素的地址),但类型不同。

根据您编写的代码,您将函数调用为

init_pop(&population);

对应的函数定义应该是

int init_pop(int (*population)[pop_size][chrome_length]) // note that both dimensions
                                                         // must be specified

你可以访问每个元素

(*population)[i][j] = initial_value;

请注意,这意味着init_pop 只能处理pop_size x chrome_length 数组;你不能在不同大小的数组上使用它。

如果你调用函数为

init_pop(population); // note no & operator

那么对应的函数定义就必须是

int init_pop(int (*population)[chrome_length]) // or population[][chrome_length],
                                               // which is equivalent

你可以访问每个元素

 population[i][j] = initial_value;

请注意,在这种情况下,您不必显式取消引用 population。现在您可以处理具有不同种群大小的数组,但您仍然被固定的染色体长度所困扰。

第三种方法是将指向数组第一个元素的指针显式传递为指向 int 的简单指针,并​​将其视为一维数组,根据数组维度手动计算偏移量(作为单独的参数传递):

init_pop(&population[0][0], pop_size, chrome_length);
...
int init_pop(int *population, size_t pop_size, size_t chrome_length)
{
  size_t i, j;
  ...
  population[i*chrome_length+j] = initial_value;
  ...
}

现在 init_pop 可以用于不同大小的 int 二维数组:

int pop1[10][10];
int pop2[15][20];
int pop3[100][10];
...
init_pop(&pop1[0][0], 10, 10);
init_pop(&pop2[0][0], 15, 20);
init_pop(&pop3[0][0], 100, 10);
...

编辑:请注意,上述技巧仅适用于连续分配二维数组;它不适用于动态分配的数组,其中主要维度和次要维度是分开分配的。

这是一个方便的表格,假设定义为int a[N][M]

表达式类型隐式转换为 ---------- ---- ------------ 一个 int [N][M] int (*)[M] a[i] 整数 [M] 整数 * a[i][j] 整数 &a 整数 (*)[N][M]

【讨论】:

  • 最冗长的答案,并且 +1 专门用于提及指向数组的指针(这似乎是此处给出要求的最佳选择)。
  • 干得好,值得提名“最佳 StackOverflow”
【解决方案2】:

在将数组作为参数传递时,您需要告诉编译器除了第一个维度之外的所有维度:

int init_pop(int population[][pop_size])
{ 
 ...
}

是的,这意味着很难让它完全动态化并引入一个你必须重复自己的地方。

更新:我很困惑,并且要求颠倒了。现已修复。

【讨论】:

  • 鉴于这个答案是完全错误的事实,这个答案被 3 票接受,这有点可怕。您需要指定除 first 之外的所有维度。
  • @Robert:谢谢,当然修好了。我应该测试一下,抱歉。
【解决方案3】:

对于 C/C++ 中的多维数组,您必须指定除第一个维度之外的所有维度。我正在修改您的程序以使其正常工作:

#include <stdio.h>
#include <stdlib.h>
#define pop_size 3
#define chrom_length 3

void init_pop(int population[][chrom_length]) {
 int i,j;
 for(i = 0; i < pop_size; i++) {
      for(j = 0; j < chrom_length; j++) {
            population[i][j] = rand() % 2;
      }
 }
}

/* For Checking */
void display (int population[][chrom_length]){
  int i,j;
 for(i = 0; i < pop_size; i++) {
      for(j = 0; j < chrom_length; j++) {
          printf("%d ",population[i][j]);
      }
      printf("\n");
    }
}


int main(void) {
 int population[pop_size][chrom_length];
 init_pop(population);
 display(population); /* For Checking */

 return 0;
}

如果你不打算使用全局常量here 是正确的做法。

【讨论】:

    【解决方案4】:

    这就是问题所在:

    int *population[][]
    

    多维数组只是一块连续的内存,当你说foo[3][2]时,编译器会通过3*last_dimension_size + 2找到正确的索引,这意味着它必须知道除最后一个之外的所有尺寸。

    所以该声明是一个错误。


    顺便说一句——在 SO 上已经有几个关于 c 中多维数组相关问题的非常完整的讨论。尝试在 [c][c++] 两者或任一下搜索

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-27
      • 2010-09-30
      • 2020-05-23
      • 2011-04-20
      相关资源
      最近更新 更多