Использование стандартных массивов
С точки зрения эффективности поменяйте местами два элемента на одну итерацию при переборе значений столбца. Поскольку ваш массив имеет фиксированную ширину, начните с начального и конечного элементов, поменяйте их местами и продолжайте работать с конца до середины, например,
void rev2d (int (*a)[COLS], int rows, int cols)
{
for (int i = 0; i < rows; i++)
for (int j = 0, k = cols - 1; j < k; j++, k--) {
int tmp = a[i][j];
a[i][j] = a[i][k];
a[i][k] = tmp;
}
}
(выше ..[j]
и ..[k]
elemnts каждый поменяется местами на каждую итерацию inner-l oop)
Или если вы хотите сделать то же самое, используя while
циклы и указатели на начальный и конечный элементы в каждой строке (кроме итерации по строкам в обратном порядке) вы можете сделать следующее:
void rev2dptrs (int (*a)[COLS], int rows, int cols)
{
while (rows--) {
int *beg = *(a + rows), *end = *(a + rows) + cols - 1;
while (end > beg) {
int tmp = *beg;
*beg++ = *end;
*end-- = tmp;
}
}
}
В каждом случае, например, если у вас есть:
#define ROWS 3
#define COLS ROWS
...
int a[][COLS] = {{ 0, 1, 2 }, { 3, 4, 5 }, { 6, 7, 8 }};
Ваш вызов функции будет:
rev2d (a, ROWS, COLS);
или во втором случае:
rev2dptrs (a, ROWS, COLS);
Просто поворот при нормальном развороте.
Использование массивов переменной длины
Первоначальная цель состояла в том, чтобы избежать примеров с VLA из-за C11 Standard - 6.7.6.2 Деклараторы массивов (p4) "Variable length arrays are a conditional feature that implementations need not support;"
и C11 Standard - 6.10.8.3 Макросы условных функций __STDC_NO_VLA__
Однако, как указано в комментариях, и с практикой реального мира Поскольку практически все основные компиляторы будут продолжать предоставлять VLA, вы можете обеспечить немного большую гибкость, изменив декларации и указав размеры rows
и cols
fist, а затем передав массив в виде VLA. Преимущество в том, что оно освобождает вас от постоянного размера. Например, но функции можно переписать, передав массив в виде VLA:
void rev2dvla (int rows, int cols, int a[rows][cols])
{
for (int i = 0; i < rows; i++)
for (int j = 0, k = cols - 1; j < k; j++, k--) {
int tmp = a[i][j];
a[i][j] = a[i][k];
a[i][k] = tmp;
}
}
и с указателями:
void rev2dptrsvla (int rows, int cols, int a[rows][cols])
{
while (rows--) {
int *beg = *(a + rows),
*end = *(a + rows) + cols - 1;
while (end > beg) {
int tmp = *beg;
*beg++ = *end;
*end-- = tmp;
}
}
}
Здесь преимущество состоит в том, что вы освобождаетесь от целого числа постоянное ограничение на количество элементов в строке. При указании параметров rows
и cols
перед параметром массива значения rows
и cols
становятся известны до того, как массив int a[rows][cols]
задан в качестве параметра, позволяющего VLA иметь полный тип.
В этом случае вызовами функций будут:
rev2dvla (rows, COLS, a);
и
rev2dptrsvla (rows, COLS, a);
Если вы понимаете каждый из способов и чем они отличаются от других - тогда у вас есть сортировка 2D массив под контролем. Дайте мне знать, если у вас есть дополнительные вопросы.
Собрав полный пример, чтобы хотя бы раз выполнить каждую из приведенных выше функций, и добавив функцию print2D, вы можете сделать что-то вроде следующего:
#include <stdio.h>
#define COLS 3
void rev2d (int (*a)[COLS], int rows, int cols)
{
for (int i = 0; i < rows; i++)
for (int j = 0, k = cols - 1; j < k; j++, k--) {
int tmp = a[i][j];
a[i][j] = a[i][k];
a[i][k] = tmp;
}
}
void rev2dptrs (int (*a)[COLS], int rows, int cols)
{
while (rows--) {
int *beg = *(a + rows),
*end = *(a + rows) + cols - 1;
while (end > beg) {
int tmp = *beg;
*beg++ = *end;
*end-- = tmp;
}
}
}
void rev2dvla (int rows, int cols, int a[rows][cols])
{
for (int i = 0; i < rows; i++)
for (int j = 0, k = cols - 1; j < k; j++, k--) {
int tmp = a[i][j];
a[i][j] = a[i][k];
a[i][k] = tmp;
}
}
void rev2dptrsvla (int rows, int cols, int a[rows][cols])
{
while (rows--) {
int *beg = *(a + rows),
*end = *(a + rows) + cols - 1;
while (end > beg) {
int tmp = *beg;
*beg++ = *end;
*end-- = tmp;
}
}
}
void prn2d (int (*a)[COLS], int rows, int cols)
{
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++)
printf (" %2d", a[i][j]);
putchar ('\n');
}
}
int main (void) {
int a[][COLS] = {{ 0, 1, 2 }, { 3, 4, 5 }, { 6, 7, 8 }},
rows = sizeof *a / sizeof **a;
puts ("original:");
prn2d (a, rows, COLS); /* print original */
rev2d (a, rows, COLS); /* reverse col values using indexes */
puts ("\nreversed using indexes:");
prn2d (a, rows, COLS); /* print reversed array */
rev2dptrs (a, rows, COLS); /* reverse reversed array to restore original */
puts ("\nrestore original using pointers:");
prn2d (a, rows, COLS); /* print original */
rev2dptrs (a, rows, COLS); /* reverse col values using pointers */
puts ("\nreverse again using pointers:");
prn2d (a, rows, COLS); /* print reversed array */
rev2dvla (rows, COLS, a); /* reverse col values restoring original */
puts ("\nrestore original using VLA w/indexes:");
prn2d (a, rows, COLS); /* print original */
rev2dvla (rows, COLS, a); /* reverse col values using indexes */
puts ("\nreversed with VLA using indexes:");
prn2d (a, rows, COLS); /* print reversed array */
rev2dptrsvla (rows, COLS, a); /* reverse reversed array to restore original */
puts ("\nrestore original using VLA w/pointers:");
prn2d (a, rows, COLS); /* print original */
rev2dptrsvla (rows, COLS, a); /* reverse col values using pointers */
puts ("\nreverse again using VLA w/pointers:");
prn2d (a, rows, COLS); /* print reversed array */
}
Пример использования / Вывод
$ ./bin/revarr2d
original:
0 1 2
3 4 5
6 7 8
reversed using indexes:
2 1 0
5 4 3
8 7 6
restore original using pointers:
0 1 2
3 4 5
6 7 8
reverse again using pointers:
2 1 0
5 4 3
8 7 6
restore original using VLA w/indexes:
0 1 2
3 4 5
6 7 8
reversed with VLA using indexes:
2 1 0
5 4 3
8 7 6
restore original using VLA w/pointers:
0 1 2
3 4 5
6 7 8
reverse again using VLA w/pointers:
2 1 0
5 4 3
8 7 6