C语言调用strcmp()比较输入与字符串数组时输出异常排查
问题场景
开发基于C语言的大调音阶生成程序(音阶间隔规则为WS,WS,HS,WS,WS,WS)时,需要使用strcmp()函数将用户输入的音名字符数组,与存储12个标准音名的字符串数组做比对,获取匹配项的索引以应用音阶生成公式。原有实现代码如下:
/*This is a program to generate notes of major scale in C programing given WS,WS,HS,WS,WS,WS */ #include <stdio.h> #include <stdint.h> #include <string.h> int main(){ int i = 0; int totalIntervals = 11; char *notes[12] = {"A", "A#", "B", "C","C#","D","D#","E","F","F#","G","G#"}; char pickedNote[2] ; for(i=0;i<12;++i){ printf("Your notes are %s\n",notes[i]); } printf("Please type in a note\n"); scanf("%s",pickedNote); printf("Your note is %s\n",pickedNote); for(i=0;i<12;++i) { int truth = strcmp(pickedNote,¬es[i]); printf("%d\n",&truth); } return 0; }
异常现象
预期用户输入A时,strcmp返回值在匹配索引位置为0,其余位置为非0值,对应输出形态为:
Your note is A 1 0 0 0 0 0 0 0 0 0 0 0
实际运行时所有比对结果输出均为异常随机整数值(如-1614868988),实际输出如下:
Your note is A -1614868988 -1614868988 -1614868988 -1614868988 -1614868988 -1614868988 -1614868988 -1614868988 -1614868988 -1614868988 -1614868988 -1614868988
问题根因
代码存在3个直接触发异常的错误,另有1个潜在内存风险:
strcmp参数类型不匹配:notes是char*类型数组,notes[i]本身就是指向音名字符串的指针,符合strcmp要求的const char*入参类型;代码写¬es[i]取的是数组元素这个指针变量的栈内存地址,类型为char**,传入strcmp后会读取非法内存,返回值完全不可预期。printf传参错误:要打印truth变量存储的strcmp返回值,直接传入变量名truth即可;代码写&truth传的是truth变量在栈上的内存地址,所以打印出来的是随机的栈地址值,和字符串比对结果没有任何关系。- 输入缓冲区长度不足:音名最长为2个有效字符(如
A#),加上C语言字符串必须的末尾结束符\0,缓冲区至少需要3字节;原有代码定义char pickedNote[2],输入带#的音名时会直接发生缓冲区溢出,破坏栈内存数据。 - 输入无长度限制:
scanf("%s")没有做输入长度截断,用户输入过长内容时会直接造成内存越界。
修正后可运行代码
/*This is a program to generate notes of major scale in C programing given WS,WS,HS,WS,WS,WS */ #include <stdio.h> #include <string.h> int main(){ int i = 0; // 大调音阶间隔:全全半全全全半,对应步长2,2,1,2,2,2,1 int majorSteps[] = {2,2,1,2,2,2,1}; char *notes[12] = {"A", "A#", "B", "C","C#","D","D#","E","F","F#","G","G#"}; // 缓冲区留足长度,scanf限制最多读2个有效字符,避免溢出 char pickedNote[3] ; int rootIndex = -1; for(i=0;i<12;++i){ printf("可选音名: %s\n",notes[i]); } printf("请输入起始音名: "); scanf("%2s",pickedNote); printf("你选择的主音是 %s\n",pickedNote); // 查找匹配的主音索引 for(i=0;i<12;++i) { int cmpRes = strcmp(pickedNote, notes[i]); if(cmpRes == 0){ rootIndex = i; break; } } if(rootIndex == -1){ printf("输入的音名无效\n"); return 1; } // 生成大调音阶 printf("对应大调音阶为: "); int current = rootIndex; printf("%s ", notes[current]); for(i=0;i<7;++i){ current = (current + majorSteps[i]) % 12; printf("%s ", notes[current]); } printf("\n"); return 0; }
内容的提问来源于stack exchange,提问作者Rudy F.
相关产品推荐
相关产品推荐

