我编写了以下代码来执行一个简单的矩阵乘法。
#include <stdio.h>
void op2(float *a_vec, int m, int n, int p, float *b_vec, float *c_vec){
float (*a)[n] = (float(*)[n]) a_vec;
float (*b)[p] = (float(*)[p]) b_vec;
float (*c)[p] = (float(*)[p]) c_vec;
int i, j, k;
for (i = 0; i<m; i++){
for(j=0; j<p; j++){
for(k=0; k<n; k++){
c[i][j] += a[i][k] * b[k][j];
}
printf("%.1f ", c[i][j]);
}
printf("\n");
}
}
int main(void){
float *aVec;
float *bVec;
float *cVec;
int m = 2;
int n = 3;
int p = 2;
float a[6] = {
1,3,1,
2,2,2
};
aVec = &a[0];
float b[6] = {
1,3,
1,2,
2,2
};
bVec = &b[0];
float c[4];
cVec = &c[0];
op2(aVec, m, n, p, bVec, cVec);
}
生成的矢量(打印到输出)应为6.0 11.0 8.0 14.0
事实上...大多数时候。
然而,有时并不是这样。有时数组的第一个值会不正确。最常见的是5.7或5.8 5.8 11.0 8.0 14.0
我的问题是,我在这里做了什么,导致了这种不一致?我对C很陌生,我最好的猜测是,也许我遗漏了一些与数组索引有关的东西,也许我跑过了数组的结尾?但是我不明白,如果它有相同的输入,它怎么会不一致,所以也许我遗漏了一些与指针有关的东西?
尝试过:在循环外声明数组变量,更改输入数组中的值。
1条答案
按热度按时间gojuced71#
只有当
c
矩阵初始化为0时,循环中才有c[i][j] += a[i][k] * b[k][j];
。但是,main
中的c
数组float c[4];
声明时没有初始化器,所以它包含垃圾,当你将乘法结果相加时,会产生更多的垃圾。valgrind
内存检查工具发现了这个bug。像这样的工具对于C调试来说是无价的,当你遇到bug时,应该首先尝试一下。AddressSanitizer(-fsanitize=address)和UBSan(-fsanitize=undefined)在愚者和clang中都有,它们也很好,但是它们碰巧没有发现这个bug。这个特殊的问题可以通过定义
float c[4] = {0.0};
来解决。(只要你初始化了数组中的至少一个元素,其余的所有元素都会自动初始化为零。)