CS50x - PSET2- 替换

CS50x - PSET2- Substitution

我在提交时遇到了问题,我没有发现我的代码有问题,当我测试它时它工作正常但出于某种原因我不知道我什么时候使用 check50,它 returns 这个结果:

:) substitution.c exists
:) substitution.c compiles
:( encrypts "A" as "Z" using ZYXWVUTSRQPONMLKJIHGFEDCBA as key
Cause
output not valid ASCII text
:( encrypts "a" as "z" using ZYXWVUTSRQPONMLKJIHGFEDCBA as key
Cause
output not valid ASCII text
:( encrypts "ABC" as "NJQ" using NJQSUYBRXMOPFTHZVAWCGILKED as key
Cause
expected "ciphertext: NJ...", not ""
:( encrypts "XyZ" as "KeD" using NJQSUYBRXMOPFTHZVAWCGILKED as key
Cause
expected "ciphertext: Ke...", not ""
:( encrypts "This is CS50" as "Cbah ah KH50" using YUKFRNLBAVMWZTEOGXHCIPJSQD as key
Cause
expected "ciphertext: Cb...", not ""
:) encrypts "This is CS50" as "Cbah ah KH50" using yukfrnlbavmwzteogxhcipjsqd as key
:( encrypts "This is CS50" as "Cbah ah KH50" using YUKFRNLBAVMWZteogxhcipjsqd as key
Cause
expected "ciphertext: Cb...", not ""
:( encrypts all alphabetic characters using DWUSXNPQKEGCZFJBTLYROHIAVM as key
Cause
expected "ciphertext: Rq...", not ""
:) handles lack of key
:) handles invalid key length
:) handles invalid characters in key
:) handles duplicate characters in key
:) handles multiple duplicate characters in key

这个结果意味着我的代码输出了错误的结果,但是当我自己测试按键和输入文本时,它按预期工作,我花了几个小时试图弄清楚,但我对我的代码一无所知:

    #include <cs50.h>
    #include <stdio.h>
    #include <string.h>
    #include <ctype.h>
    #include <math.h>

    bool contains(char c, char arr[], int n)
    {
        for(int i = 0 ;i < n; i++)
        {
        if(c == arr[i])
        {
            return true;
        }
    }
    return false; 
    }

    bool validkey(string key)
    {
    if (strlen(key) != 26 )
    {
        return false;
    }
    char l[26];
    for (int i = 0; i < 26; i++)
    {
        if(isalpha(key[i]))
        {
            if(contains(key[i],l,i))
            {
                return false;
            }
            else
            {
                l[i] = key[i];
            }
        }
        else
        {
            return false;
        }
    }
    return true;

    }

    void cypher(string key, string s)
    {
    int n = strlen(s);

    char r[n+1];
    char t;
    char a = 'a';
    int pos = 0;
    char w;

    for(int i = 0; i < n; i++)
    {

        if(isalpha(s[i])){
            t = tolower(s[i]);
            pos = t - a;
            if (islower(s[i]))
            {
                r[i]= tolower(key[pos]);

            }
            else if (isupper(s[i]))
            {
                r[i] = toupper(key[pos]);

            }
        }
        else
        {
            r[i] = s[i];

        }
    }
    r[n]='[=11=]';
    printf("ciphertext: %s\n",r);
    }


    int main(int argc, string argv[])
    {
    if(argc != 2)
    {
     return 1;
    }
    string key = argv[1];
    if(!validkey(key))
    {
        printf("Invalid");
        return 1;
    }
    string q = get_string("plain text: ");
    cypher(key,q);

    return 0;

}

您的实际问题似乎是您忽略了在未提供输入或提供无效密钥的情况下所需的简单输出,例如来自 Pset2 - Substitution

如果用户没有提供有效密钥怎么办?

$ ./substitution ABC
Key must contain 26 characters.

还是真的不配合?

$ ./substitution
Usage: ./substitution key

您未能在每种情况下提供正确的输出。

现在您的代码有点粗糙,正如 @EugeneSh 在评论中指出的那样。你的 contains() 有点尴尬和多余。您需要的是一个简单的频率阵列。一个包含 26 个整数的数组,初始化为全零,您可以在其中映射 key 中的字符 0-25(通过转换 char tolower() 并减去 'a' 因此 a-z 映射到 0-25。然后对于 key 中的每个字符,您只需检查 array[tolower(key[i]) - 'a'] 是否是重复的字符和 return false。如果不是,则递增该元素并检查下一个字符,例如:

#define KEYSZ 26

bool validkey (string key)
{
    int keychk[KEYSZ] = {0};
    
    if (strlen (key) != KEYSZ) {
        return false;
    }
    
    for (int i = 0; key[i]; i++) {
        int lowerk = tolower(key[i]) - 'a';
        
        if (!isalpha (key[i]) || keychk[lowerk])
            return false;
        
        keychk[lowerk]++;
    }
    
    return true;
}

其中 keychk[] 数组用于该目的。

您的 cypher() 函数实际上应该 return 键入 string 以便调用函数可以使用密文,而不仅仅是输出。 (这不是错误,只是实际考虑)。您可以将 cypher() 函数(重命名为:encipher())重写并简化为:

string encipher (string key, string s, string cipher)
{
    int i = 0;
    
    for (; s[i]; i++) {
        if (isalpha (s[i])) {
            int pos = tolower (s[i]) - 'a';
            cipher[i] = islower(s[i]) ? tolower(key[pos]) : toupper(key[pos]);
        }
        else
            cipher[i] = s[i];
    }
    cipher[i] = 0;
    
    return cipher;
}

这真的是唯一需要的两个功能。如果你把它放在一起,你会得到:

#include <cs50.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define KEYSZ 26

bool validkey (string key)
{
    int keychk[KEYSZ] = {0};
    
    if (strlen (key) != KEYSZ) {
        return false;
    }
    
    for (int i = 0; key[i]; i++) {
        int lowerk = tolower(key[i]) - 'a';
        
        if (!isalpha (key[i]) || keychk[lowerk])
            return false;
        
        keychk[lowerk]++;
    }
    
    return true;
}

string encipher (string key, string s, string cipher)
{
    int i = 0;
    
    for (; s[i]; i++) {
        if (isalpha (s[i])) {
            int pos = tolower (s[i]) - 'a';
            cipher[i] = islower(s[i]) ? tolower(key[pos]) : toupper(key[pos]);
        }
        else
            cipher[i] = s[i];
    }
    cipher[i] = 0;
    
    return cipher;
}

int main (int argc, string argv[])
{
    if (argc < 2) {
        fputs ("Usage: ./substitution key\n", stderr);
        return 1;
    }

    size_t len = 0;
    string key = argv[1];

    if (!validkey (key)) {
        fputs ("Key must contain 26 characters.\n", stderr);
        return 1;
    }

    string plain = get_string ("plaintext:  "), cipher;

    len = strlen (plain);
    cipher = malloc (len + 1);

    printf ("ciphertext: %s\n", encipher (key, plain, cipher));

    free (cipher);

    return 0;
}

(注意: main() 更新为单独分配 cipher 分配 plain 中的字符数 (+1nul-terminating 字符)并根据问题更改了输出提示,例如 "plaintext ""ciphertext: ",并添加了 #include <stdlib.h> 而不是默认包含在线 ide.cs50.io CS50 IDE)

试一试,如果您有问题或需要其他帮助,请告诉我。