Передача многомерного массива переменного размера указателем в C - PullRequest
1 голос
/ 23 декабря 2010

Я пытаюсь передать двумерный массив переменного размера в функцию для его печати.Я знаю, как это сделать, когда у вас есть фиксированные размеры массивов.Но как это сделать с массивами переменного размера?Вот некоторый код, который даст вам представление о том, что я пытаюсь сделать:

void print_grid(char (*g)[9], int size) // the array subscript (9 here) be variable
{
   int i, j;
   for (i=0; i<size; i++)
   {
      for (j=0; j<size; j++)            
         printf("%c ", g[i][j]);
      printf("\n");
   }
}

Я назову эту функцию, используя следующий код:

char a[3][3], b[9][9];
// assign a, b
print_grid(a, 3);
print_grid(b, 9);

Есть лиспособ сделать это без выделения динамической памяти в print_grid ()?

Ответы [ 4 ]

5 голосов
/ 23 декабря 2010
void print_grid(int rows, int cols, char g[][cols]) { ... }
1 голос
/ 16 февраля 2012

Когда вы передаете массив в C, он всегда передается по ссылке, то есть через указатель.Тип этого указателя не указатель на массив , а указатель на первый элемент .Например, генератор кода будет обрабатывать void f(char[][10]), как если бы он был void f(char*).Размеры массива потеряны.Парсер, однако, будет жаловаться, если увидит, что f объявлен дважды так.

Мотивация C заключалась в том, чтобы иметь мощный и переносимый ассемблер, а не новый язык программирования.Многомерные массивы - это логические конструкции, которых нет в машине.Массивы - это способ мышления.

Чтобы передать размеры массивов в функции, программисты на C традиционно используют struct s:

typedef struct array_tag {
    int count;
    char data[1]; /* actually data[count] */
} ARRAY;

typedef struct grid_tag {
    int rows, columns;
    char grid[1][1]; /* actually grid[rows][columns] */
} GRID;

void f(ARRAY* x)
{
    int i;
    for (i = 0; i < x->count; ++i) {
        char c = x->data[i];
    }
}

void g(GRID* x)
{
    int i, j;
    for (i = 0; i < x->rows; ++i)
        for (j = 0; j < x->columns; ++j) {
            char c = x->grid[i][j];
        }
}

void h()
{
    {
        const int len = 100;
        ARRAY* x = (ARRAY*) malloc(sizeof(ARRAY) + len * sizeof(char));
        x->count = len;
        f(x);
    }

    {
        const int rows = 2, cols = 3;
        GRID* x = (GRID*) malloc(sizeof(GRID) + rows * cols * sizeof(char));
        x->rows = rows;
        x->columns = cols;
        g(x);
    }
}

Да, выражение malloc в этом примере выделяет слишком мало байт.Поэтому GNU-компилятор поддерживает массивы нулевой длины в течение длительного времени , что недопустимо в C90.

C99 продвинулся на один шаг вперед с гибкими массивами.Из ИСО / МЭК 9899: 1999, раздел 6.7.2.1, параграф 16: "В особом случае последний элемент структуры с более чем одним именованным элементом может иметь неполный тип массива; это называется гибким массивомmember. " В C99 типы ARRAY и GRID могут быть объявлены как:

typedef struct array_tag {
    int count;
    char data[]; /* actually data[count] */
} ARRAY;

typedef struct grid_tag {
    int rows, columns;
    char grid[][1]; /* actually grid[rows][columns] */
} GRID;

, и вы можете

assert(1*sizeof(int) == sizeof(ARRAY));
assert(2*sizeof(int) == sizeof(GRID));

Многие люди думают, что массивы C причудливы,Но они также являются элегантным решением, которое позволяет объявлять бесконечно сложные массивы.Он известен как «уравнение массива K & R».Хорошее объяснение можно найти здесь .

Надеюсь, это поможет.

1 голос
/ 23 декабря 2010
void print_grid(char *g, int size) 
{
   int i, j;

   for( i = 0; i < size; i++)
      for( j = 0; j < size; j++)
      {
         printf("%c ", *(g + i*size + j));
         printf("\n");
      }
}

print_grid(a, 3);
0 голосов
/ 23 декабря 2010

Этот делает это , предполагая квадратную сетку:

void print_grid(void* g, int size)
{
  char* my = (char*) g;
  int i, j;
  for (i=0; i<size; i++)
  {
    for (j=0; j<size; j++)            
       printf("%c ", my[i+j]);
    printf("\n");
  }
}

Если вы хотите использовать сетки без квадратов, замените size на rows и columns параметр и настройка счета: i<rows и j<columns.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...