使用标准数组
从效率的角度来看,在迭代列值时,每次迭代交换两个元素。由于您的数组具有固定宽度,因此从开头和结尾元素开始,交换它们,然后从结尾继续工作到中间,例如
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] 元素之上,每个内部循环的迭代都会交换)
或者,如果您想使用 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);
只是正常反转的一个转折。
使用可变长度数组
最初的意图是避免由于C11 Standard - 6.7.6.2 Array declarators(p4) "Variable length arrays are a conditional feature that implementations need not support;" 和C11 Standard - 6.10.8.3 Conditional feature macros __STDC_NO_VLA__ 而导致的VLA示例
但是,正如 cmets 中所指出的那样,并且由于几乎所有主要编译器都将继续提供 VLA 的实际实用性,您可以通过反转声明并指定 rows 和 cols 来提供更多的灵活性大小拳头,然后将数组作为 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 参数,在将数组int a[rows][cols] 指定为允许VLA 成为完整类型的参数之前,rows 和cols 的值是已知的。
函数调用将是:
rev2dvla (rows, COLS, a);
和
rev2dptrsvla (rows, COLS, a);
如果您了解每种方式以及它们与其他方式的不同之处,那么您就可以控制对二维数组进行排序。如果您还有其他问题,请告诉我。
将完整示例放在一起,至少对上面的每个函数进行一次练习并添加一个 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