【问题标题】:C: Function to swap values in 2D arrayC:交换二维数组中的值的函数
【发布时间】:2009-09-30 23:36:51
【问题描述】:

我正在尝试编写一个函数来交换二维数组中的 2 个元素:

void swap(int surface[][], int x1, int y1, int x2, int y2) {
    int temp = surface[x1][y1];
    surface[x1][y1] = surface[x2][y2];
    surface[x2][y2] = temp;
}

但是,当我尝试编译它 (gcc) 时,我收到以下错误消息:

Sim_Annealing.c: In function `swap': 
Sim_Annealing.c:7: error: invalid use of array with unspecified bounds
Sim_Annealing.c:8: error: invalid use of array with unspecified bounds
Sim_Annealing.c:8: error: invalid use of array with unspecified bounds
Sim_Annealing.c:9: error: invalid use of array with unspecified bounds

为了将二维数组作为函数参数,我需要做一些特殊的事情吗?

感谢您的帮助。如果您知道数组作为函数参数的任何好的参考资料,请按我的方式发送:)

【问题讨论】:

  • 请在您投票关闭“完全重复”时发表评论,说明什么这是完全重复的。
  • @Lutz,您可以通过单击“关闭”然后投票“完全重复”来查看建议的重复项列表。在这种情况下,这个人提出了这个问题:stackoverflow.com/questions/4051/…
  • 但是,没有足够代表投票关闭的用户无法以这种方式查看建议的副本。在很多情况下,这将包括最初提出问题的人。
  • @stephentyrone:无论声誉如何,您都可以随时投票结束自己的问题。因此,您可以在实际关闭之前查看您自己问题的关闭原因。
  • 好的,我添加了一个使用 C99 引入的完全通用的可变长度数组参数的示例。请注意,C99 最初并未得到广泛支持,而且大多数实现仍不完全符合要求。

标签: c arrays function-parameter


【解决方案1】:

只需声明数组参数。更好的是,对初始声明和函数的形参都使用 typedef。

问题是在不知道行大小(即列数)的情况下,它无法计算指针调整以获得后续行。有趣的是,它不需要知道你有多少行。

例如,这是有效的:

void swap(int surface[][20], int x1, int y1, int x2, int y2) {
  int temp = surface[x1][y1];
    surface[x1][y1] = surface[x2][y2];
    surface[x2][y2] = temp;
}

但最好将调用者的类型和函数的类型绑定在一起。


每个下标访问都需要乘法,但这有效(仅符合 C99 的编译器)...

int f(int, int, int a[*][*]);

int f(int r, int c, int a[r][c])
{
  return a[99][100];
}

另一个例子,它甚至可以在 C89 之前的环境中工作:

typedef int surface_t[][20];

surface_t therealthing = {
  { 1, 2, 3},
  { 4, 5, 6}
};

void swap(surface_t x) {
  x[0][2] = 'q';
}

void f1(void) {
  swap(therealthing);
}

最后,因为可变长度数组是最近才出现的,传统的也是最快的技术是通过int *a[]。这不需要任何关于行或列长度的知识,但您确实需要构造指针向量。

【讨论】:

  • 如果我想让函数处理可变大小的二维数组怎么办?
  • @Casey,将数组的维度作为参数传递,或使用例如std::vector.
【解决方案2】:

如果数组是“真实的”二维数组,则需要指定除第一个维度之外的所有维度的大小:

void swap(int surface[][NUMBER_OF_COLUMNS], int x1, int y1, int x2, int y2) {
    ...
}

这有一些潜在的问题。如果您的 2D 数组确实是指针数组 (int *surface[]),那将不起作用,您需要将 surface 参数更改为指向指针的指针:

void swap(int **surface, int x1, int y1, int x2, int y2) {
    ...
}

或者,为了使函数更通用,您可以将其更改为接受两个 int 指针(可以指向任何地方)并交换它们:

void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

你会这样称呼它:

swap(&surface[x1][y1], &surface[x2][y2]);

【讨论】:

  • 您必须指定第二个维度,即列数。
  • 是的,我刚刚注意到并修复了它。谢谢。
【解决方案3】:

在 C 中,只允许不指定数组的第一个维度,因为它需要知道如何计算偏移量。如果您需要使用可变大小的 2D 数组作为 int* 传入我们的数组,请自行传入第二维的大小和指针数学:

void swap(int *surface, int ySize, int x1, int y1, int x2, int y2) {
    int temp = *(surface + ySize * x1 + y1) ;
    *(surface + ySize * x1 + y1) = *(surface + ySize * x2 + y2);
    *(surface + ySize * x2 + y2) = temp;
}

这与 [][] 语法的作用相同,因为 C 中的数组实际上只是指针。

【讨论】:

    【解决方案4】:

    GCC 允许可变长度数组作为函数的参数:

    #include <stdio.h> 
    
    void swap(int size; int surface[][size], int size, int x1, int y1, int x2, int y2) {
      int temp = surface[x1][y1];
      surface[x1][y1] = surface[x2][y2];
      surface[x2][y2] = temp;
    }
    
    int s[10][10];
    
    int main(){
      s[1][1] = 11;
      s[2][2] = 22;
    
      printf("s[1][1]: %i   s[2][2]: %i\n", s[1][1], s[2][2] );
      swap( s, 10, 1, 1, 2, 2 );
      printf("s[1][1]: %i   s[2][2]: %i\n", s[1][1], s[2][2] );
    
      return 0;
    }
    

    【讨论】:

    • +1;我不认为我会在实际代码中使用它,但这是一个巧妙的技巧:)
    【解决方案5】:

    将多维数组作为函数参数传递会带来一些麻烦。请记住,在大多数情况下,数组类型的表达式将被隐式转换为指针类型,其值将是数组第一个元素的地址。例如,一个 10x20 的 int 数组将被转换为一个指向 20 元素的 int 数组的指针:

    void swap(int (*surface)[20], size_t rows, size_t x1, size_t x2, 
              size_t y1, size_t y2)
    {
      int temp;
      assert(x1 < rows && x2 < rows);
      temp = surface[x1][y1];
      surface[x1][y1] = surface[x2][y2];
      surface[x2][y2] = temp;
    }
    int main(void)
    {
      int surface[10][20];
      ...
      swap(surface, 10, 1, 1, 2, 2);
      ...
    }
    

    这里出现了一个大问题。基于其原型,swap() 只能处理 Nx20 个 int 数组;行数可以变化,但列数不能,因为T (*)[N]T (*)[M] 的类型不同,其中 N != M。理想情况下,您需要一个可以处理任意行数的函数 列。实现此目的的一种方法是将数组视为 T 的一维数组,并手动计算行和列偏移:

    void swap(int *surface, size_t rows, size_t cols, size_t x1, 
              size_t x2, size_t y1, size_t y2)
    {
      int temp;
      assert(x1 < rows && x2 < rows && y1 < cols && y2 < cols);
      temp = surface[x1*cols+y1];
      surface[x1*cols+y1] = surface[x2*cols+y2];
      surface[x2*cols+y2] = temp;
    }
    int main(void)
    {
      int surface[10][20];
      ...
      swap(&surface[0][0], 10, 20, 1, 1, 2, 2);
    }
    

    这里我们传递第一个元素的地址 (&surface[0][0]) 并将其视为指向 int 的简单指针。这样我们就可以处理任意数量的行和列。请注意,这仅适用于实际的 2D 数组(而不是指针数组),因为 swap 假定数组元素是连续布局的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-15
      • 1970-01-01
      • 2021-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多