更改并包装关键字整数,在C中不使用循环

问题描述 投票:0回答:1

我正在编写一个程序,该程序在命令提示符下接受字符串,然后将字符串的每个字符转换为字母的相应0-25数字。然后,每个数字都用于对用户在程序提示后输入的另一个字符串的每个字符进行加密。第二个字符串的每个字母字符应与整数字符串的顺序匹配,如果第二个字符串较长,则整数字符串将换行。该程序的目标是使用第一个字符串作为键来移动消息的每个字符(第二个字符串)。

示例(期望的输出):用户运行程序并输入关键字:bad

提示用户仅输入字母和标点符号的字符串:Dr. Oz

程序将关键字“坏”转换为1,0,3

程序将消息加密到Er. Ra

我实际上得到的是:

… T.B.S. …

我已经尝试了很多事情,但是不幸的是,我似乎无法弄清楚如何在不循环第二条消息的情况下循环和包装密钥。如果您运行该程序,将会看到我的问题。

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

int shift(char key1);

int main(int argc, string argv[]) // user enter number at cmd prompt
{
    if (argv[1] == '\0')
    {
        printf("Usage: ./vigenere keyword\n");
        return 1;
    }
    string key = argv[1]; // declare second arg as string
    for (int i = 0, n = strlen(key); i < n; i++)
        if (isdigit(key[i]) != 0 || argc != 2)
        {
            printf("Usage: ./vigenere keyword\n");
            return 1;
        }
    string text = get_string("plaintext: ");
    printf("ciphertext: ");
    int k;
    char t;

    for (int j = 0, o = strlen(text); j < o; j++)
    {
        t = text[j];
        for (int i = 0, n = strlen(key); i < n; i++)
        {
            k = shift(key[i]);
            if (isupper(t))
            {
                t += k;
                if (t > 'Z')
                {
                    t -= 26;
                }
            }
            if (islower(t))
            {
                t += k;
                if (t > 'z')
                {
                    t -= 26;
                }
            }
            printf("%c", t);
        }
    }

    printf("\n");
}

int shift(char key1)
{
    int k1 = key1;
    if (islower(key1))
    {
        k1 %= 97;
    }
    if (isupper(key1))
    {
        k1 %= 65;
    }
    return k1;
}

我非常感谢您的帮助和建议,但请记住,解决方案应与我的程序建议的编码水平相匹配。可能有许多高级方法可以编写此程序,但是不幸的是,我们仍处于本课程的开始,因此向我展示新方法(我一定会尝试理解)是可以的。

encryption cs50 vigenere
1个回答
0
投票
#include <cs50.h> #include <stdio.h> #include <string.h> #include <ctype.h> int shift(char key1); int main(int argc, string argv[]) // user enter number at cmd prompt { if (argc != 2 || argv[1][0] == '\0') { fprintf(stderr, "Usage: ./vigenere keyword\n"); return 1; } string key = argv[1]; // declare second arg as string for (int i = 0, n = strlen(key); i < n; i++) { if (!isalpha(key[i])) { fprintf(stderr, "Usage: ./vigenere keyword\n"); return 1; } } string text = get_string("plaintext: "); printf("ciphertext: "); int keylen = strlen(key); int keyidx = 0; for (int j = 0, o = strlen(text); j < o; j++) { int t = text[j]; if (isupper(t)) { int k = shift(key[keyidx++ % keylen]); t += k; if (t > 'Z') t -= 26; } else if (islower(t)) { int k = shift(key[keyidx++ % keylen]); t += k; if (t > 'z') t -= 26; } printf("%c", t); } printf("\n"); } int shift(char key1) { if (islower(key1)) key1 -= 'a'; if (isupper(key1)) key1 -= 'A'; return key1; }

正好将两个参数和一个非空键的测试移到顶部。这与评论中的建议略有不同。错误消息将打印为标准错误,而不是标准输出。我可能将第二个“使用”消息替换为更具体的错误-the key may only contain alphabetic characters或附近。错误应该包括argv[0]作为程序名称,而不是硬编码名称。密钥验证循环将检查密钥是否全部为字母,而不是检查其是否不是数字-字符类多于数字和字母。该代码使用keyidxkeylen来跟踪键的长度和键中的位置。我使用单字母变量名称,但通常仅用于循环索引或简单指针(通常是指向字符串的指针);否则,我使用短的半助记符名称。有两个对shift()的调用,因此keyidx仅在输入字符为字母时才递增。还有其他方式可以对此进行编码。

注释中没有预言的一个非常重要的变化是t的类型从char更改为int。当它是char时,如果用字母后面的字母(例如z)加密字母y,则值'z' + 24会溢出Intel计算机上普遍存在的(有符号)char类型,负值(最典型的表示;行为未定义)。这导致伪造的输出。更改为int可解决该问题。由于将t的值传递给int时仍会提升为printf(),因此在打印中不会造成任何危害。

我决定不在k1中使用额外的局部变量shift()。我还用减法代替了注释中提到的模数。

鉴于从cc59创建的程序cc59.c,示例运行为:

$ cc59 bad plaintext: Dr. Oz ciphertext: Er. Ra $ cc59 zax plaintext: Er. Ra ciphertext: Dr. Oz $ cc59 ablewasiereisawelba plaintext: The quick brown fox jumps over the lazy dog. Pack my box with five dozen liquor jugs. The five boxing wizards jump quickly. How vexingly quick daft zebras jump. Bright vixens jump; dozy fowl quack. ciphertext: Tip uqius fisef fkb uvmpt zzar lpi cehq dkk. Abck nj fkx oqxy jqne zskfn ljbykr bckj. Xpw fezp coxjyk sirivuw rmml ufjckmj. Lkw nmbzrody mytdk dbqx vetzej ncep. Xvthht wtbank rydt; lgzu jzxl qvlgg. $ cc59 azpweaiswjwsiaewpza plaintext: Tip uqius fisef fkb uvmpt zzar lpi cehq dkk. Abck nj fkx oqxy jqne zskfn ljbykr bckj. Xpw fezp coxjyk sirivuw rmml ufjckmj. Lkw nmbzrody mytdk dbqx vetzej ncep. Xvthht wtbank rydt; lgzu jzxl qvlgg. ciphertext: The quick brown fox jumps over the lazy dog. Pack my box with five dozen liquor jugs. The five boxing wizards jump quickly. How vexingly quick daft zebras jump. Bright vixens jump; dozy fowl quack. $

通过将数据的第1行中的“加密”字母与数据第2行中的解密字母进行匹配来推导出解密密钥:

abcdefghijklmnopqrstuvwxyz
azyxwvutsrqponmlkjihgfedcb

使用加密和解密,对代码进行的最基本的酸性测试是,程序可以在给定正确的解密密钥和密文的情况下解密自己的加密输出。

© www.soinside.com 2019 - 2024. All rights reserved.