C语言中如何不区分大小写检查字符串无重复字符?含指针错误
CS50替换密码密钥检查:重复字符检测失效与strcasecmp参数疑问
问题描述
我是编程新手,正在学CS50的替换密码作业。写了一段C代码检查密钥是否符合要求:26个字母、无重复(不区分大小写),但现在两个问题:
- 重复字符的检查完全失效,输入有重复的密钥也不会触发错误提示
- 编译时必须给变量c和d加&才能通过,想知道原因
附上我的代码:
#include <cs50.h> #include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <string.h> #include <strings.h> int main(int argc, string argv[]) { int len = strlen(argv[1]); if(len != 26) { printf("Usage: ./substitution key\n"); return 1; } if(argc != 2) { printf("Usage: ./substitution key\n"); return 1; } for(int i = 0; i < len; i++) { if(isdigit(argv[1][i]) || ispunct(argv[1][i])) { printf("Usage: ./substitution key\n"); return 1; } for(int j = 0; j < len; j++) { char c = argv[1][i]; char d = argv[1][j]; int value = strcasecmp(&d, &c); if(value != 0) { printf("Usage: ./substitution key\n"); return 1; } } } }
问题解决
1. 为什么需要给c和d加&?
strcasecmp函数的定义是int strcasecmp(const char *s1, const char *s2),它要求传入字符串指针(指向以'\0'结尾的字符数组)。你定义的c和d是单个char变量,不是完整字符串。要让strcasecmp能处理它们,必须用&取变量的地址,让函数把这个地址当作长度为1的字符串来处理(虽然单个字符后面没有'\0',但函数只比较第一个字符,所以能正常工作)。
其实单个字符的不区分大小写比较,用tolower()或toupper()转换后直接对比更简单,没必要用strcasecmp,比如:
if(tolower(c) == tolower(d))
2. 重复字符检测逻辑错误
你的嵌套循环逻辑完全搞反了:现在的代码是对每个字符i,遍历所有j,只要i和j的字符不相等就报错,这意味着只有当26个字符完全相同时才不会报错,和你要检测「无重复」的需求完全相反。
正确的逻辑应该是:
- 先检查
argc != 2,这一步必须放在最前面,不然如果用户没传参数,argv[1]会导致越界访问 - 对每个字符i,只和它后面的字符j(j从i+1开始)比较,如果发现不区分大小写相等的字符,说明有重复,触发错误
- 字符合法性检查用
isalpha(),因为除了数字和标点,还有空格、制表符等非字母字符,直接判断非字母就报错
修正后的代码:
#include <cs50.h> #include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <string.h> #include <strings.h> int main(int argc, string argv[]) { // 先检查参数数量,避免argv[1]越界 if(argc != 2) { printf("Usage: ./substitution key\n"); return 1; } int len = strlen(argv[1]); if(len != 26) { printf("Usage: ./substitution key\n"); return 1; } for(int i = 0; i < len; i++) { // 检查是否为字母 if(!isalpha(argv[1][i])) { printf("Usage: ./substitution key\n"); return 1; } // 只和i之后的字符比较,避免重复检查和自比 for(int j = i + 1; j < len; j++) { // 不区分大小写比较 if(strcasecmp(&argv[1][i], &argv[1][j]) == 0) { printf("Usage: ./substitution key\n"); return 1; } } } // 如果所有检查通过,可继续后续逻辑 printf("Key is valid!\n"); return 0; }
修正点说明
- 把
argc != 2的检查移到最前面,防止空指针访问 - 用
!isalpha()替代原来的数字+标点检查,覆盖所有非字母情况 - 内层循环从
j = i + 1开始,只比较当前字符之后的字符,减少不必要循环,同时避免自己和自己比较 - 发现任意一对重复字符时立即报错退出,符合需求
内容的提问来源于stack exchange,提问作者AbhijitDoesCoding
相关产品推荐
相关产品推荐

