C语言topMatches函数输出非法随机浮点数问题排查求助
我是C语言初学者,学习时遇到问题:topMatches()函数输出的scores数组首尾出现超出[-1,1]范围的随机浮点数,示例输出如下:
Output #1
(-0.00000, Lisa Rose),(0.99124, Gene Seymour),(0.92447, Michael Phillips),(0.89341, Claudia Puig),(0.66285, Mick LaSalle),(0.38125, Jack Matthews),(-1.00000, Toby)
Output #2
(107185664961793568883398204719104.00000, Lisa Rose),(0.99124, Gene Seymour),(0.92447, Michael Phillips),(0.89341, Claudia Puig),(0.66285, Mick LaSalle),(0.38125, Jack Matthews),(-1.00000, Toby)
Output #3
(0.99124, Lisa Rose),(0.92447, Gene Seymour),(0.89341, Michael Phillips),(0.66285, Claudia Puig),(0.38125, Mick LaSalle),(-118195603315995709432961818167345152.00000, Jack Matthews),(-1.00000, Toby)
...
scores数组每个元素值应处于[-1,1]范围内,以下是我的代码:
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> //data types struct mInfo { char mName[20]; float rating; }; struct cInfo { char name[20]; struct mInfo movi[7]; }; //prototype fxns typedef double (*sim_fp)(struct cInfo *, const char *, const char *); double sim_D(struct cInfo *prefs, const char *person1, const char *person2); void topMatches(sim_fp fp, struct cInfo *prefs, const char *person1, int num); int cmpFxn (const void * a, const void * b); void reverseFxn(float arr[], int num); int main() { int num = 7; struct cInfo critics[num]; critics[0] = (struct cInfo) {"Lisa Rose", {"Lady in the Water", 2.5, "Snakes on a Plane", 3.5, "Just My Luck", 3, "Superman Returns", 3.5, "The Night Listener", 3, "You, Me and Dupree", 2.5}}; critics[1] = (struct cInfo) {"Gene Seymour",{"Lady in the Water", 3, "Snakes on a Plane", 3.5, "Just My Luck", 1.5, "Superman Returns", 5, "The Night Listener", 3, "You, Me and Dupree", 3.5}}; critics[2] = (struct cInfo) {"Michael Phillips",{"Lady in the Water", 2.5, "Snakes on a Plane", 3, "Superman Returns", 3.5, "The Night Listener", 4}}; critics[3] = (struct cInfo) {"Claudia Puig",{"Snakes on a Plane", 3.5, "Just My Luck", 3, "Superman Returns", 4, "The Night Listener", 4.5, "You, Me and Dupree", 2.5}}; critics[4] = (struct cInfo) {"Mick LaSalle",{"Lady in the Water", 3, "Snakes on a Plane", 4, "Just My Luck", 2, "Superman Returns", 3, "The Night Listener", 3, "You, Me and Dupree", 2}}; critics[5] = (struct cInfo) {"Jack Matthews",{"Lady in the Water", 3, "Snakes on a Plane", 4, "Superman Returns", 5, "You, Me and Dupree", 3.5}}; critics[6] = (struct cInfo) {"Toby",{"Snakes on a Plane", 4.5, "Superman Returns", 4, "You, Me and Dupree",1}}; topMatches(sim_D, critics, "Toby", 7); return 0; } double sim_D(struct cInfo *prefs, const char *person1, const char *person2) { int i=0; int x=0; int next=0; int p1; int p2; float X = 0; float Y = 0; float sumSq1 = 0; float sumSq2 = 0; float pSum = 0; float num = 0; float den = 0; float Pscore = 0; int nElements =0; for (i=0;i<7;i++) { if(strcmp(prefs[i].name, person1) ==0) { p1 = i; } else if(strcmp(prefs[i].name, person2) ==0) { p2 = i; } } for (x=0;x<7;x++) { for (next=0;next<7;next++) { if (!prefs[p1].movi[x].rating && !prefs[p2].movi[next].rating); else if (strcmp(prefs[p1].movi[x].mName, prefs[p2].movi[next].mName) == 0) { X += prefs[p1].movi[x].rating; Y += prefs[p2].movi[next].rating; sumSq1 += pow(prefs[p1].movi[x].rating,2); sumSq2 += pow(prefs[p2].movi[next].rating,2); pSum += (prefs[p1].movi[x].rating*prefs[p2].movi[next].rating); nElements++; } } next = 0; } num = pSum-(X*Y/nElements); den=sqrt((sumSq1-pow(X,2)/nElements)*(sumSq2-pow(Y,2)/nElements)); if(den ==0) return -1; Pscore = num/den; return Pscore; } void topMatches(sim_fp fp, struct cInfo *prefs, const char *person1, int num) { float scores[8]; char *buf; int i=0; for (i=0;i<num;i++) { if(strcmp(person1, prefs[i].name)==0) { continue; } scores[i] = fp(prefs, person1, prefs[i].name); } qsort(scores, num, sizeof(float), (*cmpFxn)); reverseFxn(scores, num); printf("\n\n"); for(i=0;i<num;i++) { if (i == num-1) { printf("(%.5f, %s)", scores[num-1], prefs[num-1].name); } else { printf("(%.5f, %s),", scores[i], prefs[i].name); } } } void reverseFxn(float arr[], int num) { float scoresTmp[num]; int j; for(j=0;j<num;j++) { scoresTmp[num-1-j] = arr[j]; } for(j=0;j<num;j++) { arr[j]=scoresTmp[j]; } } int cmpFxn (const void * a, const void * b) { return ( *(int*)a - *(int*)b ); }
问题排查与修复
1. scores数组存在未初始化的元素
在topMatches()的循环中,当遇到和person1同名的元素时,用continue跳过赋值,导致对应索引的scores[i]保留栈上的随机垃圾值。比如查询"Toby"时,i=6被跳过,scores[6]未初始化,后续排序后这个随机值会出现在数组中。
修复:跳过前给对应位置赋值,比如设为-1(自身相似度无需计算):
for (i=0;i<num;i++) { if(strcmp(person1, prefs[i].name)==0) { scores[i] = -1; // 明确赋值,避免随机值 continue; } scores[i] = fp(prefs, person1, prefs[i].name); }
2. qsort比较函数类型错误
cmpFxn错误地将float指针转为int指针取值比较,导致浮点数被截断,排序逻辑完全错误,还可能引发未定义行为。
修复:正确处理float类型比较:
int cmpFxn(const void *a, const void *b) { const float *fa = (const float*)a; const float *fb = (const float*)b; if (*fa < *fb) return -1; if (*fa > *fb) return 1; return 0; }
3. 排序后分数与人名对应关系断裂
直接对scores数组排序,但未同步排序对应的人名,导致输出时分数和人名错位。比如排序后scores[0]是最高相似度,但prefs[0].name还是原来的Lisa Rose,两者不再匹配。
修复:创建结构体绑定分数和索引,排序后按索引输出:
// 新增结构体用于绑定分数和索引 struct ScoreIndex { float score; int index; }; // 修改topMatches函数 void topMatches(sim_fp fp, struct cInfo *prefs, const char *person1, int num) { struct ScoreIndex scoreIndices[num]; int i=0; for (i=0;i<num;i++) { scoreIndices[i].index = i; if(strcmp(person1, prefs[i].name)==0) { scoreIndices[i].score = -1; continue; } scoreIndices[i].score = fp(prefs, person1, prefs[i].name); } // 修改比较函数适配ScoreIndex qsort(scoreIndices, num, sizeof(struct ScoreIndex), (int (*)(const void*, const void*))compareScoreIndex); printf("\n\n"); for(i=0;i<num;i++) { int idx = scoreIndices[i].index; if (i == num-1) { printf("(%.5f, %s)", scoreIndices[i].score, prefs[idx].name); } else { printf("(%.5f, %s),", scoreIndices[i].score, prefs[idx].name); } } } // 新增ScoreIndex的比较函数 int compareScoreIndex(const void *a, const void *b) { const struct ScoreIndex *sa = (const struct ScoreIndex*)a; const struct ScoreIndex *sb = (const struct ScoreIndex*)b; if (sa->score < sb->score) return -1; if (sa->score > sb->score) return 1; return 0; }
4. sim_D函数中p1、p2未初始化风险
如果循环中未找到指定的person1或person2,p1和p2会是随机值,导致后续数组访问越界。
修复:初始化p1、p2为-1,循环后检查是否找到:
int p1 = -1, p2 = -1; for (i=0;i<7;i++) { if(strcmp(prefs[i].name, person1) ==0) { p1 = i; } if(strcmp(prefs[i].name, person2) ==0) { p2 = i; } } if (p1 == -1 || p2 == -1) { return -1; // 未找到指定人物,返回默认值 }
内容的提问来源于stack exchange,提问作者Saucdp

