为什么循环有问题(pset2 替换)

Why the loops has a problem (pset2 Substitution)

我一直在进行 CS50X pset2 替换。我认为它几乎已经完成了。当我输入单个字符时,例如 AB D 等等......密文将得到正确的结果。 (例如 A 将得到 J,"B" 将得到 TD 将得到 E 等等...

但是,如果我输入ABC,密文只会显示J,其他的不能显示。我做错了什么?

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


int ciphertext = 0;

//Key
//JTREKYAVOGDXPSNCUIZLFBMWHQ

int main(int argc, string argv[])
{
     //Check that program was run with one command-line argument
    if (argc == 2)
    {

        string key = argv[1];



        //check the key does it validate
        for (int i = 0, n = strlen(key); i < n; i++)
        {

            string plaintext = get_string("plaintext: ");
            printf("ciphertext: \n");

            int u = 64;


            for (int k = 0, p = strlen(plaintext); k < p; k++)
            {
                if (isupper(plaintext[k]) != 0)
                {
                    for (int j = 0; j < 26; j++)
                    {

                        u = u + 1;
                        //printf("u is %c\n", u);


                        if (u == plaintext[k])
                        {
                            ciphertext = key[j];
                            printf("Key is %c\n", key[j]);
                            printf("Plaintext is %c\n", plaintext[k]);
                            printf("ciphertext is %c\n", ciphertext);
                            //break;
                        }

                    }
                }

                else
                {
                    printf("%c", plaintext[k]);
                }
            }

            return 0;
        }
    }
}

您的问题是逻辑错误,似乎是由于您试图对失控的代码进行更改而导致的。您的代码中有不必要的循环和未使用的变量。您需要更改 u 声明的范围,以便在每次迭代时重新初始化它。您只需要完全删除 for (int i = 0, n = strlen(key); i < n; i++) 循环,既不使用 i 也不使用 nciphertextl (ell) 相同。

您需要在 if (isupper(plaintext[k])) 之后立即移动 int u = 64;,以便在每次迭代时重置它。

我怀疑所有 printf 语句都是为了调试,你真的只想要 key 输出。总而言之,您可以将代码重新排列为:

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

int main (int argc, string argv[]) {

    if (argc == 2) {    /* validate key given */

        string key = argv[1];
        string plaintext = get_string("plaintext: ");
        printf("ciphertext: ");

        for (int k = 0, p = strlen(plaintext); k < p; k++) 
        {
            if (isupper(plaintext[k])) 
            {
                int u = 64;
                for (int j = 0; j < 26; j++) 
                {
                    u = u + 1;
                    if (u == plaintext[k]) {
                        printf("%c", key[j]);
                        break;
                    }
                }
            }
            else
                printf("%c", plaintext[k]);
        }
        putchar ('\n');
    }
}

例子Use/Output

$ ./bin/cs50_cypher2 JTREKYAVOGDXPSNCUIZLFBMWHQ
plaintext: ABD
ciphertext: JTE

简化你的逻辑

如果你仔细想想上面的代码实际上在做什么,它可以简化为:

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

int main (int argc, string argv[]) {

    if (argc < 2) {    /* validate key given */
        fputs ("usage: ./program key\n", stderr);
        return 1;
    }

    string key = argv[1];
    string plaintext = get_string("plaintext: ");
    printf("ciphertext: ");

    for (int k = 0, p = strlen(plaintext); k < p; k++) 
    {
        if (isupper(plaintext[k]))
            putchar (key[plaintext[k] - 'A']);
        else
            putchar (plaintext[k]);
    }
    putchar ('\n');
}

或者,如果您使用 三元 运算符,您的 for 循环将简化为:

    for (int k = 0, p = strlen(plaintext); k < p; k++) 
        putchar (isupper(plaintext[k]) ? key[plaintext[k] - 'A'] : plaintext[k]);

并且由于不需要调用 strlen(plaintext),您可以完全消除 string.h 并只循环 for (int k = 0; plaintext[k]; k++) 因为 plaintext 是一个以 nul 结尾的字符串,您的整个程序可以减少到:

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

int main (int argc, string argv[]) {

    if (argc < 2) {    /* validate key given */
        fputs ("usage: ./program key\n", stderr);
        return 1;
    }

    string key = argv[1];
    string plaintext = get_string("plaintext : ");
    printf("ciphertext: ");

    for (int k = 0; plaintext[k]; k++) 
        putchar (isupper(plaintext[k]) ? key[plaintext[k] - 'A'] : plaintext[k]);

    putchar ('\n');
}

处理小写字母[=7​​8=]

您知道您输入的 key 作为第一个参数全部大写。因此,如果要输出小写 key,则必须在应用偏移量后对键调用 tolower()。由于对于大写字母,您只想知道要使用的 26 个字符键内的偏移量,您只需找出当前字母来自 'A' 的多少个字母,然后在 key[] 中获取该偏移量,例如

    key[plaintext[k] - 'A']

对于小写输入,需要在key中找出小写字母差异的偏移量,然后将tolower()应用于key,例如

    tolower(key[plaintext[k] - 'a'])

ASCII Table & Description

总而言之,您的 for 循环可以写成:

    for (int k = 0; plaintext[k]; k++) {
        if (isupper(plaintext[k]))
            putchar (key[plaintext[k] - 'A']);
        else if (islower(plaintext[k]))
            putchar (tolower(key[plaintext[k] - 'a']));
        else
            putchar (plaintext[k]);
    }

例子Use/Output

$ ./bin/cs50_cypher4 JTREKYAVOGDXPSNCUIZLFBMWHQ
plaintext : AbZ 50
ciphertext: JtQ 50

检查一下,如果您还有其他问题,请告诉我。

我也尝试检测低调,但结果不是我想要的。我输入"AbZ 50"。假设答案是"JtQ 50"。然而,它是"JTQ 50"

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

int main (int argc, string argv[]) {

    if (argc == 2) {    /* validate key given */

        string key = argv[1];
        string plaintext = get_string("plaintext: ");
        printf("ciphertext: ");

        for (int k = 0, p = strlen(plaintext); k < p; k++)
        {
            if (isupper(plaintext[k]))
            {
                int u = 64;
                for (int j = 0; j < 26; j++)
                {
                    u = u + 1;
                    if (u == plaintext[k]) {
                        printf("%c", key[j]);
                        break;
                    }
                }
            }
            else if (islower(plaintext[k]))
            {
                int l = 96;
                for (int j = 0; j < 26; j++)
                {
                    l = l + 1;
                    if (l == plaintext[k]) {
                        printf("%c", key[j]);
                        break;
                    }
                }
            }
            else
                printf("%c", plaintext[k]);
        }
        putchar ('\n');
    }
}