【问题标题】:Swap sub-arrays of a multi-dimensional array in C在C中交换多维数组的子数组
【发布时间】:2017-06-18 05:02:15
【问题描述】:

我有一个 50 x 50 矩阵 arr[50][50],需要交换子数组 arr[0]arr[1] 中的值。 即,每个子数组中的全部 50 个元素需要交换。

我能想到的唯一方法是使用如下循环:

for(i=0; i<50; ++i)
{
    int t = arr[0][i];
    arr[0][i] = arr[1][i];
    arr[1][i] = t;
}

我想知道是否有更简单或更短的方法?可以使用指针吗?

我尝试过类似

int *t = arr[0];
arr[0] = arr[1];
arr[1] = t;

但它在第一行给出了关于“从类型'int *'分配给类型'int [2]'时不兼容的类型”的错误。

然后我尝试了指向数组的指针

int (*t)[50] = arr[0];
arr[0] = arr[1];
arr[1] = t;

这一次我在第二行得到了关于“从类型'int *'分配给类型'int [50]'时不兼容的类型”的错误。

【问题讨论】:

  • 嗯,一种更快的方法是使用异或表达式而不是使用第三个变量 - arr[0][i] = arr[0][i]^arr[1][i]; arr[1][i] = arr[0][i]^arr[1][i]; arr[0][i] = arr[0][i]^arr[1][i];,复杂性相同,但常数因素会发生变化。
  • 使用= 复制数据的唯一方法是从简单变量、单个数组元素或struct。考虑使用int temp[50]memcpy
  • @GAURANG VYAS:完全相反。 faster 方法是不混淆代码并帮助编译器确定您只想交换两个值。您的 XOR 技巧是一个臭名昭著的反模式,必须避免。
  • @GAURANGVYAS OP 的交换循环在每次迭代中执行 3 次读取和 3 次写入(i 除外),但您的方式执行 6 次读取和 3 次写入。
  • @GAURANG VYAS:与第三个变量的简单交换将立即被体面的编译器识别为交换操作。编译器将能够以最有效的方式实现它:可能是一条 XCHNG 指令,甚至可能是您的 XOR 技巧,也可能是其他东西。编译器更擅长这种微优化。同时,您的 XOR 技巧可能只会混淆编译器并阻碍这些优化。

标签: c arrays pointers gcc


【解决方案1】:

如果您的矩阵实现为arr[50][50],那么物理交换两行的唯一方法是物理交换内存中的数据。你的周期是一种方法。其余的只是这种方法的变体。您可以一个接一个地交换矩阵元素(您的循环),您可以使用中间行大小的缓冲区交换整个行(memcpy 方法)。他们所有人仍然做同样的事情。没有办法解决。

如果您的数组以不同的方式实现 - 例如,一个“锯齿状”数组实现为子数组的 指针 数组,那么您将能够交换两个指针并完成它。但在arr[50][50] 的情况下,这是不可能的。

如果您愿意,您可以通过单独的行指针数组将当前数组“转换”为“锯齿状”版本。该行指针数组现在将成为您的矩阵a,而原来的a[50][50] 将成为a_data

int a_data[50][50];

int *a[50];
for (unsigned i = 0; i < 50; ++i)
  a[i] = a_data[i];

/* Fill the matrix */
for (unsigned i = 0; i < 50; ++i)
  for (unsigned j = 0; j < 50; ++j)
    a[i][j] = rand();

/* Print the matrix */
for (unsigned i = 0; i < 50; ++i)
{
  for (unsigned j = 0; j < 50; ++j)
    printf("%d ", a[i][j]);
  printf("\n");
}

/* Swap the rows */
int *temp = a[0];
a[0] = a[1];
a[1] = temp;

/* Print the matrix */
for (unsigned i = 0; i < 50; ++i)
{
  for (unsigned j = 0; j < 50; ++j)
    printf("%d ", a[i][j]);
  printf("\n");
}

请注意,尽管a 的物理结构现在有所不同,但您仍然可以使用a[i][j] 语法来处理它。

【讨论】:

    【解决方案2】:

    如 cmets 和其他答案中所述,为了交换实际二维数组的行(与指针数组相对),您必须将数据从源复制/移动到内存中的目标行.解决此问题的最直接方法是使用循环将逐个元素复制到临时存储以实现交换,或使用 C 库提供的内存复制功能(例如 memcpymemmove) .使用memcopy 的简单实现(出于示例的目的使用3x10 数组作为数组)将是:

    #include <stdio.h>
    #include <string.h>
    
    enum { ROW = 3, COL = 10 };
    
    void swaprow (int (*a)[COL], int c1, int c2);
    void prna (int (*a)[COL]);
    
    int main (void) {
    
        int a[ROW][COL] = {{0}};
    
        for (int i = 0; i < ROW; i++)
            for (int j = 0; j < COL; j++)
                a[i][j] = i;
    
        prna (a);
        swaprow (a, 0, 1);
        putchar ('\n');
        prna (a);
    
        return 0;
    }
    
    void swaprow (int (*a)[COL], int c1, int c2)
    {
        int tmp[COL];
    
        memcpy (tmp, a[c1], COL * sizeof *tmp);
        memcpy (a[c1], a[c2], COL * sizeof *a[c1]);
        memcpy (a[c2], tmp, COL * sizeof *a[c2]);
    }
    
    void prna (int (*a)[COL])
    {
        for (int i = 0; i < ROW; i++) {
            for (int j = 0; j < COL; j++)
                printf ("%2d", a[i][j]);
            putchar ('\n');
        }
    
    }
    

    使用/输出示例

    $ ./bin/array2d_swap_row
     0 0 0 0 0 0 0 0 0 0
     1 1 1 1 1 1 1 1 1 1
     2 2 2 2 2 2 2 2 2 2
    
     1 1 1 1 1 1 1 1 1 1
     0 0 0 0 0 0 0 0 0 0
     2 2 2 2 2 2 2 2 2 2
    

    查看一下,如果您有任何问题,请告诉我。

    【讨论】:

    • 感谢您的示例!
    【解决方案3】:

    您必须复制要与memcpy 交换的数据,我已经为程序提供了示例来展示您如何做到这一点(即交换 arr[0] 和 arr[1])。

    int main(void) {
        // your code goes here
        int t[3];
        int arr[3][3]={{1,2,3},{4,5,6},{7,8,9}};
        printf("\n%d %d %d",arr[0][0],arr[0][1],arr[0][2]);
        printf("\n%d %d %d",arr[1][0],arr[1][1],arr[1][2]);
        memcpy(t,arr[0],sizeof(t));
        memcpy(arr[0],arr[1],sizeof(t));
        memcpy(arr[1],t,sizeof(t));
        printf("\n%d %d %d",arr[0][0],arr[0][1],arr[0][2]);
        printf("\n%d %d %d",arr[1][0],arr[1][1],arr[1][2]);
        return 0;
    }
    

    【讨论】:

    • @weather Vane,是的,我之前曾采用 4 * 4 矩阵,现在更正了
    • 感谢您的示例
    猜你喜欢
    • 1970-01-01
    • 2014-03-26
    • 2021-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多