C: функция для обмена значениями в 2D массиве - PullRequest
0 голосов
/ 01 октября 2009

Я пытаюсь написать функцию для замены двух элементов в двумерном массиве:

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

Есть ли какая-то особая магия, которую я должен сделать, чтобы получить двумерный массив в качестве параметра функции?

Спасибо за вашу помощь. Если вам известны какие-либо хорошие ссылки на массивы в качестве параметров функции, отправьте их мне:)

Ответы [ 5 ]

6 голосов
/ 01 октября 2009

Просто объявите параметры массива. Еще лучше, используйте 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[]. Это не требует каких-либо знаний о длине строки или столбца, но вам нужно построить указатель вектора.

1 голос
/ 01 октября 2009

Передача многомерных массивов в качестве аргументов функции вызывает некоторые головные боли. Помните, что в большинстве случаев выражение типа массива будет неявно преобразовано в тип указателя, а его значением будет адрес первого элемента массива. Так, например, массив int 10x20 будет преобразован в указатель на массив из 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. Таким образом, мы можем иметь дело с любым количеством строк и столбцов. Обратите внимание, что это будет работать только для реальных двумерных массивов (не массивов указателей), так как в swap предполагается, что элементы массива расположены последовательно.

1 голос
/ 01 октября 2009

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 голос
/ 01 октября 2009

В C разрешено не указывать только первое измерение массива, поскольку оно должно знать, как рассчитать смещения. Если вам нужно работать с двумерным массивом переменного размера, передайте в нашем массиве как 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 на самом деле просто указатели.

1 голос
/ 01 октября 2009

Если массив является «реальным» 2D-массивом, вам нужно указать размер всего, кроме первого измерения:

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]);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...