You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言中如何不区分大小写检查字符串无重复字符?含指针错误

CS50替换密码密钥检查:重复字符检测失效与strcasecmp参数疑问

问题描述

我是编程新手,正在学CS50的替换密码作业。写了一段C代码检查密钥是否符合要求:26个字母、无重复(不区分大小写),但现在两个问题:

  1. 重复字符的检查完全失效,输入有重复的密钥也不会触发错误提示
  2. 编译时必须给变量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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 08:27:39