C语言编程中strcmp用法是否有误?仅识别Large输入问题排查
问题描述
实现C语言饮品规格输入校验逻辑:用户输入内容不属于Small/small/Large/large四个合法值时,持续提示重新输入。实际运行时仅输入Large可通过校验,其余三个合法值均被判定为非法。
问题复现代码
#include <stdio.h> #include <string.h> int main() { char drinksize[5]; do { printf("\nEnter Drink Size (Small or Large): "); scanf("%s", drinksize); if(strcmp(drinksize, "Small") == 1 || strcmp(drinksize, "small") == 1 || strcmp(drinksize, "Large") == 1 || strcmp(drinksize, "large") == 1) { printf("Incorrect item number! Please try again."); } } while (strcmp(drinksize, "Small") == 1 || strcmp(drinksize, "small") == 1 || strcmp(drinksize, "Large") == 1 || strcmp(drinksize, "large") == 1); }
错误原因
核心问题是strcmp的使用存在两处明显错误,同时附带一个内存安全隐患:
- 对
strcmp返回值规则理解错误
C标准仅规定strcmp的三类返回结果,没有要求返回固定的1/-1:- 两个字符串完全相等时,返回值固定为
0 - 第一个字符串字典序大于第二个字符串时,返回任意正整数(不同编译环境、不同libc实现下可能是1、32或其他正数值,不能依赖返回值等于1做判断)
- 第一个字符串字典序小于第二个字符串时,返回任意负整数
- 两个字符串完全相等时,返回值固定为
- 输入合法性判定逻辑完全写反
原代码将「和任意一个合法值比较结果等于1」作为非法输入判定条件,完全不符合字符串相等判断逻辑。结合当前环境下strcmp的返回值表现,四个字符串的字典序为Large < Small < large < small:- 输入
Large时,和四个合法值比较的结果分别为负、负、0、负,没有等于1的返回值,因此被误判为合法,退出循环 - 输入其余三个合法值时,总会存在和某一个合法值比较返回正整数1的情况,因此被误判为非法,持续循环
- 输入
- 缓冲区溢出隐患
定义的drinksize数组长度仅为5,且scanf("%s")未限制读取长度,用户输入超过4个字符时会越界写入内存,触发未定义行为。
修复后代码
正确逻辑为:输入和四个合法值比较全部不相等时,才判定为非法需要重输,同时增加输入长度限制避免越界:
#include <stdio.h> #include <string.h> int main() { // 预留足够数组长度 char drinksize[16]; do { printf("\nEnter Drink Size (Small or Large): "); // 限制最大读取长度为15,避免缓冲区溢出 scanf("%15s", drinksize); // 所有合法值均不匹配时提示错误 if(strcmp(drinksize, "Small") != 0 && strcmp(drinksize, "small") != 0 && strcmp(drinksize, "Large") != 0 && strcmp(drinksize, "large") != 0) { printf("Incorrect item number! Please try again.\n"); } // 循环条件与错误判定逻辑一致,输入非法则继续循环 } while (strcmp(drinksize, "Small") != 0 && strcmp(drinksize, "small") != 0 && strcmp(drinksize, "Large") != 0 && strcmp(drinksize, "large") != 0); // 后续业务逻辑 printf("Input valid, drink size: %s\n", drinksize); return 0; }
内容的提问来源于stack exchange,提问作者Jian
相关产品推荐
相关产品推荐

