C 语言实例 – 矩阵转换(完整教程)

C 语言实例 – 矩阵转换:从二维数组到数据重塑

在学习 C 语言的过程中,二维数组是一个绕不开的核心知识点。它不仅是程序处理表格数据的基础,更是许多算法问题的基石。而“矩阵转换”作为二维数组操作中的经典场景,常常出现在图像处理、数学建模、游戏开发等实际应用中。

本文将带你一步步理解 C 语言中如何实现矩阵转换,包括常见的转置、旋转、翻转等操作。通过真实代码示例和详细注释,即使是初学者也能轻松掌握这些技巧。如果你正在准备面试,或者想提升自己的数组操作能力,这篇文章就是为你准备的。


什么是矩阵转换?

在数学中,矩阵是由数字按行和列排列形成的矩形阵列。在编程中,我们通常用二维数组来表示矩阵。例如,一个 3×3 的矩阵可以表示为:

1  2  3
4  5  6
7  8  9

而“矩阵转换”指的是对这个矩阵进行某种规则的重新排列。常见的转换包括:

  • 转置:将行变为列,列变为行
  • 旋转:顺时针或逆时针旋转 90°、180°
  • 翻转:水平或垂直翻转

这些操作在图像处理中非常常见。比如,一张照片旋转 90°,其实就是对像素矩阵进行一次旋转操作。


创建数组与初始化

在 C 语言中,二维数组是连续存储的。我们可以通过静态定义或动态分配来创建。这里以静态方式为例:

#include <stdio.h>

int main() {
    // 定义一个 3x3 的二维数组,用于表示矩阵
    int matrix[3][3] = {
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9}
    };

    // 输出原始矩阵
    printf("原始矩阵:\n");
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            printf("%d ", matrix[i][j]);
        }
        printf("\n");
    }

    return 0;
}

代码说明:

  • int matrix[3][3]:声明一个 3 行 3 列的整型二维数组。
  • 初始化时使用嵌套的大括号 {},每行对应一个内层数组。
  • 外层 for 循环控制行,内层控制列,逐个输出元素。
  • 每行结束后用 printf("\n") 换行,使输出更清晰。

运行结果如下:

原始矩阵:
1 2 3 
4 5 6 
7 8 9 

这个结构就像一张表格,每一行是一个“数据行”,每一列是一个“数据列”。理解这一点,是进行矩阵转换的前提。


实现矩阵转置

转置是将矩阵的行和列互换。例如,原本第 i 行第 j 列的元素,转置后会出现在第 j 行第 i 列。

我们来实现一个转置函数:

#include <stdio.h>

// 转置函数:将原矩阵转置并存入新矩阵
void transpose(int matrix[3][3], int transposed[3][3]) {
    // 外层循环:遍历原矩阵的行
    for (int i = 0; i < 3; i++) {
        // 内层循环:遍历原矩阵的列
        for (int j = 0; j < 3; j++) {
            // 关键逻辑:将 matrix[i][j] 放到 transposed[j][i]
            transposed[j][i] = matrix[i][j];
        }
    }
}

int main() {
    int matrix[3][3] = {
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9}
    };

    int transposed[3][3]; // 存放转置结果

    // 调用转置函数
    transpose(matrix, transposed);

    // 输出转置后的矩阵
    printf("转置后的矩阵:\n");
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            printf("%d ", transposed[i][j]);
        }
        printf("\n");
    }

    return 0;
}

代码说明:

  • transpose 函数接收两个参数:原矩阵和目标矩阵。
  • transposed[j][i] = matrix[i][j] 是转置的核心逻辑——交换行列索引。
  • 注意:目标矩阵必须有足够空间,否则会越界。

输出结果为:

转置后的矩阵:
1 4 7 
2 5 8 
3 6 9 

你可以想象成:把一张表格从“横着看”变成“竖着看”,每一行变成一列。


实现矩阵旋转(顺时针 90°)

顺时针旋转 90° 是一个更复杂的操作。我们可以借助转置 + 翻转来实现。

步骤如下:

  1. 先对矩阵进行转置
  2. 再对每一行进行水平翻转(左右互换)
#include <stdio.h>

// 水平翻转:每一行左右对调
void flip_horizontal(int matrix[3][3]) {
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3 / 2; j++) {
            // 交换第 j 列与第 (2-j) 列的元素
            int temp = matrix[i][j];
            matrix[i][j] = matrix[i][2 - j];
            matrix[i][2 - j] = temp;
        }
    }
}

// 旋转 90 度顺时针:先转置,再水平翻转
void rotate_90_clockwise(int matrix[3][3]) {
    // 步骤1:转置
    for (int i = 0; i < 3; i++) {
        for (int j = i + 1; j < 3; j++) {
            // 只处理上三角,避免重复交换
            int temp = matrix[i][j];
            matrix[i][j] = matrix[j][i];
            matrix[j][i] = temp;
        }
    }

    // 步骤2:水平翻转
    flip_horizontal(matrix);
}

int main() {
    int matrix[3][3] = {
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9}
    };

    printf("旋转前:\n");
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            printf("%d ", matrix[i][j]);
        }
        printf("\n");
    }

    rotate_90_clockwise(matrix);

    printf("旋转 90 度顺时针后:\n");
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            printf("%d ", matrix[i][j]);
        }
        printf("\n");
    }

    return 0;
}

代码说明:

  • rotate_90_clockwise 函数中,第一层循环只处理 j > i 的部分,避免重复交换。
  • flip_horizontal 通过循环前半列与后半列交换实现。
  • 旋转后结果为:
旋转 90 度顺时针后:
7 4 1 
8 5 2 
9 6 3 

这个操作就像把一张纸从桌面旋转 90°,右上角变成左上角。


实现矩阵翻转(垂直翻转)

垂直翻转是指上下对调。第 0 行和最后一行交换,第 1 行和倒数第二行交换。

#include <stdio.h>

// 垂直翻转:上下对调
void flip_vertical(int matrix[3][3]) {
    for (int i = 0; i < 3 / 2; i++) {
        for (int j = 0; j < 3; j++) {
            // 交换第 i 行与第 (2-i) 行
            int temp = matrix[i][j];
            matrix[i][j] = matrix[2 - i][j];
            matrix[2 - i][j] = temp;
        }
    }
}

int main() {
    int matrix[3][3] = {
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9}
    };

    printf("翻转前:\n");
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            printf("%d ", matrix[i][j]);
        }
        printf("\n");
    }

    flip_vertical(matrix);

    printf("垂直翻转后:\n");
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            printf("%d ", matrix[i][j]);
        }
        printf("\n");
    }

    return 0;
}

输出结果为:

垂直翻转后:
7 8 9 
4 5 6 
1 2 3 

这就像把一张照片从上往下倒过来。


通用化处理:动态矩阵转换

上面的例子都是固定大小的 3×3 矩阵。但在实际应用中,矩阵大小可能不确定。我们可以使用动态内存分配来支持任意大小。

#include <stdio.h>
#include <stdlib.h>

// 动态分配二维数组
int** create_matrix(int rows, int cols) {
    int** matrix = (int**)malloc(rows * sizeof(int*));
    for (int i = 0; i < rows; i++) {
        matrix[i] = (int*)malloc(cols * sizeof(int));
    }
    return matrix;
}

// 释放动态矩阵内存
void free_matrix(int** matrix, int rows) {
    for (int i = 0; i < rows; i++) {
        free(matrix[i]);
    }
    free(matrix);
}

// 通用转置函数(支持任意大小)
void transpose_dynamic(int** matrix, int** transposed, int rows, int cols) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            transposed[j][i] = matrix[i][j];
        }
    }
}

int main() {
    int rows = 3, cols = 4;

    // 创建原矩阵和转置矩阵
    int** matrix = create_matrix(rows, cols);
    int** transposed = create_matrix(cols, rows);

    // 初始化原矩阵
    int value = 1;
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            matrix[i][j] = value++;
        }
    }

    // 执行转置
    transpose_dynamic(matrix, transposed, rows, cols);

    // 输出结果
    printf("原始 %d x %d 矩阵:\n", rows, cols);
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("%2d ", matrix[i][j]);
        }
        printf("\n");
    }

    printf("\n转置后 %d x %d 矩阵:\n", cols, rows);
    for (int i = 0; i < cols; i++) {
        for (int j = 0; j < rows; j++) {
            printf("%2d ", transposed[i][j]);
        }
        printf("\n");
    }

    // 释放内存
    free_matrix(matrix, rows);
    free_matrix(transposed, cols);

    return 0;
}

关键点:

  • 使用 malloc 为每行分配内存,形成“行指针数组”。
  • 转置时需注意行列顺序。
  • 最后必须调用 free 释放内存,避免内存泄漏。

小结

通过本文,我们系统地学习了 C 语言中常见的矩阵转换操作:转置、旋转、翻转,并提供了完整的代码示例和详细注释。这些操作虽然看似简单,却是许多高级算法(如图像处理、矩阵运算、游戏逻辑)的基础。

C 语言实例 – 矩阵转换 不仅帮助你掌握二维数组的使用,也培养了你对数据结构的敏感度。记住,编程不是死记硬背,而是理解“为什么这样写”。每一次循环、每一次索引交换,背后都有其逻辑意义。

希望你能动手运行这些代码,尝试修改矩阵大小,甚至加入输入功能,让程序更灵活。编程之路,始于实践。继续加油!