数组与矩阵运算:矩阵加法、乘法,转置矩阵的 C 语言实现
矩阵运算,说白了就是批量处理数据的一种方式。我在做图像处理项目时,经常要跟矩阵打交道——比如把一张图片的像素值做转置,或者把两个滤镜矩阵做乘法。你想想看,如果没有数组,这些操作得写多少行代码?
今天我们就来聊聊矩阵的三种基本运算:加法、乘法、转置。我会用 C 语言把它们一一实现,顺便分享一些我踩过的坑。
1. 矩阵的存储方式
在 C 语言里,矩阵通常用二维数组表示。我个人习惯用 int matrix[ROW][COL] 这种静态方式,但如果矩阵大小不确定,也可以用动态内存分配。
举个例子,一个 3×3 的矩阵:
#define ROW 3
#define COL 3
int A[ROW][COL] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
嗯,这里要注意:数组下标从 0 开始,别搞混了。我曾经在项目里因为下标越界,查了半天 bug,最后发现是 for 循环多跑了一次。
2. 矩阵加法
矩阵加法很简单——对应位置元素相加。前提是两个矩阵的行数和列数必须相同。
来看代码:
void matrix_add(int A[ROW][COL], int B[ROW][COL], int C[ROW][COL]) {
for (int i = 0; i < ROW; i++) {
for (int j = 0; j < COL; j++) {
C[i][j] = A[i][j] + B[i][j];
}
}
}
为什么用两层循环?因为矩阵是二维的,外层循环控制行,内层循环控制列。说白了,就是挨个儿把每个位置的值加起来。
3. 矩阵乘法
矩阵乘法比加法复杂一些。假设 A 是 m×n 矩阵,B 是 n×p 矩阵,结果 C 是 m×p 矩阵。C 中第 i 行第 j 列的元素,等于 A 的第 i 行与 B 的第 j 列对应元素乘积之和。
公式长这样:
C[i][j] = Σ (A[i][k] * B[k][j]) // k 从 0 到 n-1
代码实现:
void matrix_multiply(int A[][3], int B[][3], int C[][3], int m, int n, int p) {
for (int i = 0; i < m; i++) {
for (int j = 0; j < p; j++) {
C[i][j] = 0;
for (int k = 0; k < n; k++) {
C[i][j] += A[i][k] * B[k][j];
}
}
}
}
这里有三层循环,你想想看:外层两个循环确定结果矩阵的每个位置,内层循环做累加。我在项目中遇到过一个问题——忘记把 C[i][j] 初始化为 0,结果算出来的值莫名其妙。嗯,从那以后我每次都会先清零。
4. 转置矩阵
转置就是把矩阵的行和列互换。A 的转置记作 AT,如果 A 是 m×n,那么 AT 就是 n×m。
实现起来也不难:
void matrix_transpose(int A[ROW][COL], int T[COL][ROW]) {
for (int i = 0; i < ROW; i++) {
for (int j = 0; j < COL; j++) {
T[j][i] = A[i][j];
}
}
}
注意看:赋值时下标是交换的。我刚开始学的时候老写反,后来记住一句话——「转置就是 T[j][i] = A[i][j]」,再也没错过。
5. 完整示例
下面我把三个运算整合到一个程序里,方便你对照:
#include <stdio.h>
#define ROW 3
#define COL 3
void matrix_add(int A[ROW][COL], int B[ROW][COL], int C[ROW][COL]) {
for (int i = 0; i < ROW; i++)
for (int j = 0; j < COL; j++)
C[i][j] = A[i][j] + B[i][j];
}
void matrix_multiply(int A[ROW][COL], int B[ROW][COL], int C[ROW][COL]) {
for (int i = 0; i < ROW; i++) {
for (int j = 0; j < COL; j++) {
C[i][j] = 0;
for (int k = 0; k < COL; k++) {
C[i][j] += A[i][k] * B[k][j];
}
}
}
}
void matrix_transpose(int A[ROW][COL], int T[COL][ROW]) {
for (int i = 0; i < ROW; i++)
for (int j = 0; j < COL; j++)
T[j][i] = A[i][j];
}
void print_matrix(int M[ROW][COL]) {
for (int i = 0; i < ROW; i++) {
for (int j = 0; j < COL; j++) {
printf("%4d ", M[i][j]);
}
printf("\n");
}
}
int main() {
int A[ROW][COL] = {{1,2,3},{4,5,6},{7,8,9}};
int B[ROW][COL] = {{9,8,7},{6,5,4},{3,2,1}};
int C[ROW][COL];
printf("矩阵 A:\n"); print_matrix(A);
printf("矩阵 B:\n"); print_matrix(B);
matrix_add(A, B, C);
printf("A + B:\n"); print_matrix(C);
matrix_multiply(A, B, C);
printf("A * B:\n"); print_matrix(C);
int T[COL][ROW];
matrix_transpose(A, T);
printf("A 的转置:\n");
for (int i = 0; i < COL; i++) {
for (int j = 0; j < ROW; j++) {
printf("%4d ", T[i][j]);
}
printf("\n");
}
return 0;
}
6. 知识体系图
下面这张图帮你理清矩阵运算的核心逻辑:
7. 避坑指南
- 下标越界: 我曾经在循环里用了
i <= ROW,结果数组越界,程序直接崩溃。记住,数组下标从 0 开始,最大到ROW-1。 - 乘法累加器未清零: 如果不把
C[i][j]初始化为 0,结果会是垃圾值。我吃过这个亏,现在每次写乘法都会先清零。 - 转置时搞反下标: 记住口诀——「转置就是
T[j][i] = A[i][j]」,写代码时多看一眼。 - 动态内存泄漏: 如果用
malloc分配矩阵,记得用free释放。我见过有人只分配不释放,内存越用越多。
好了,今天就聊到这里。矩阵运算看起来简单,但写对并不容易。建议你亲手敲一遍代码,跑一跑,看看结果对不对。遇到问题别慌,回头看看这篇笔记,应该能帮你解决大部分坑。