密码函数在输出的最后一个字符中产生不需要的结果

Cipher Function Producing Unwanted Results in the Last Character of Output

我一整天都在想弄清楚我创建的这个加密函数做错了什么。

该函数的工作原理是输入一个关键字,然后将其转换为 ASCII 值,然后将该值格式化为可与字母索引一起使用的内容 eg: A= 0, B= 1, C= 2, etc... 然后将所有普通文本使用相同的方法。之后它移动纯文本的字符,然后添加关键字中的字符值,循环遍历关键字,直到完成对纯文本的加密。

它适用于我的所有测试,除了一个像这样的测试:

Keyword is BaZ

输入:

plaintext: BaRFoo

输出:

ciphertext: CaQGoh

但所需的输出是

ciphertext: CaQGon

我正在使用以下加密函数:

void encipher(char* plainText, char*key)
{
    printf("ciphertext: ");
    char alphabeticalIndex[26] = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
    int currentKeyChar = 0;

    for(int i = 0, n = strlen(plainText); i < n; i++)
    {
            // check if the end of they key has been reached, if so then reset it
            if(currentKeyChar >= strlen(key)) currentKeyChar = 0;


            if(isalpha(plainText[i]) == false) printf("%c", plainText[i]);

            if(isupper(plainText[i]))
            {
                // find the cipher character as an int then add it as the key to captialCharNum
                int capitalCipherCharNum = ((int) key[currentKeyChar] - 65);
                int capitalCharNum = (((int) plainText[i] - 65) + capitalCipherCharNum) % 26;

                printf("%c", toupper(alphabeticalIndex[capitalCharNum]));
            }

            if(islower(plainText[i]))
            {
                // same as it was for capitals but in this case its lowercase
                int lowerCipherCharNum = ((int) key[currentKeyChar] - 97);
                int lowerCharNum = (((int) plainText[i] - 97) + lowerCipherCharNum) % 26;

                printf("%c", tolower(alphabeticalIndex[lowerCharNum]));
            }
        currentKeyChar++;
        }

    printf("\n");
}

你的错误在这里:

            int lowerCipherCharNum = ((int) key[currentKeyChar] - 97);

key[currentKeyChar]大写时,lowerCipherCharNum为负数,导致你的密码值错误。要解决您需要的问题:

            int lowerCipherCharNum;
            if (islower (key[currentKeyChar]))
                lowerCipherCharNum = key[currentKeyChar] - 'a';
            else
                lowerCipherCharNum = key[currentKeyChar] - 'A';

这将更正您的预期输出。

虽然使用 数组索引 来处理每个字符串并没有错,但是使用 指针算法 可以大大简化您的代码. (你也有不必要的和重复的调用 strlen 应该被删除(或者至少通过计算 key 的长度一次而不是每次检查它来最小化。))

使用指针算法如何简化逻辑的示例(并缩短变量名,因为我不喜欢打字),您可以执行类似于以下操作的操作:

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

void encipher (const char *plaintext, const char *key)
{
    const char *aidx = "abcdefghijklmnopqrstuvwxyz",
               *p = plaintext,
               *k = key;

    printf ("ciphertext: ");

    while (*p) {
        if (isalpha (*p) == 0) printf ("%c", *p);

        if (isupper (*p)) {
            /* find the cipher character as an int then add it as the key */
            int ccicn = (*k - 'A');
            int ccnum = (*p - 'A' + ccicn) % 26;

            putchar (toupper (aidx[ccnum]));
        }

        if (islower (*p)) {
            /* same as it was for capitals but in this case its lowercase */
            int lcicn = islower (*k) ? *k - 'a' : *k - 'A';
            int lcnum = (*p - 'a' + lcicn) % 26;

            putchar (aidx[lcnum]);
        }
        p++;
        if (*k)  k++;
        if (!*k) k = key;
    }
    putchar ('\n');     /* don't use printf for one-character */
}

int main (int argc, char **argv) {

    const char *s   = argc > 1 ? argv[1] : "BaRFoo", 
               *key = argc > 2 ? argv[2] : "BaZ";

    encipher (s, key);

    return 0;
}

示例Use/Output

$ ./bin/encipher
ciphertext: CaQGon

(注:评论/* don't use printf for one-character */)

虽然不是错误,但 C 的标准编码风格避免使用 camelCaseMixedCase 变量名,而是使用所有 小写 同时保留 大写 名称以用于宏和常量。这是一个风格问题——因此完全取决于您,但不遵循它可能会导致在某些圈子中产生错误的第一印象。

下面是你的 encipher 函数的 "edited" 版本,在注释中添加了一些额外的想法,代码间距更宽一些(随着你的眼睛变老,你可能会更欣赏它)

/* if plainText and key are not modified, pass them as 'const char *' */
void encipher (const char *plainText, const char *key)
{
    /* place variables before executed code if you have the option...
     * (just increases portability to older compilers (like Win7))
     */
    char alphabeticalIndex[26] = "abcdefghijklmnopqrstuvwxyz";
    int currentKeyChar = 0;
    size_t keylen = strlen (key);

    printf ("ciphertext: ");

    for (int i = 0, n = strlen (plainText); i < n; i++)
    {
        // check if the end of they key has been reached, if so then reset it
        if (currentKeyChar >= (int)keylen) currentKeyChar = 0;

        if (isalpha (plainText[i]) == 0) putchar (plainText[i]);

        if (isupper (plainText[i]))
        {
            // find the cipher character as an int then add it as the key
            int capitalCipherCharNum = ((int) key[currentKeyChar] - 65);
            int capitalCharNum = (plainText[i] - 65 + capitalCipherCharNum) % 26;

            putchar (toupper (alphabeticalIndex[capitalCharNum]));
        }

        if (islower (plainText[i]))
        {
            // same as it was for capitals but in this case its lowercase
            // int lowerCipherCharNum = ((int) key[currentKeyChar] - 97);
            int lowerCipherCharNum;
            if (islower (key[currentKeyChar]))
                lowerCipherCharNum = key[currentKeyChar] - 'a';
            else
                lowerCipherCharNum = key[currentKeyChar] - 'A';

            int lowerCharNum = (plainText[i] - 97 + lowerCipherCharNum) % 26;

            putchar (tolower (alphabeticalIndex[lowerCharNum]));
        }
        currentKeyChar++;
    }

    putchar ('\n');     /* don't use printf for one-character */
}

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