C 中的凯撒密码向二维字符串数组添加额外字符

Caesar Cipher in C adds extra characters to 2d string array

我在堆栈溢出上看到过类似的答案,但是none遇到了和我一样的问题。这个简单的凯撒密码加密函数的问题是,对于我的加密数组的位置 [2](并且仅在位置 [2]),一个 (^3) 符号,后跟位置 [3] 处的加密字符串被连接到它。

    void encryptIDS(char login_ids[5][6])
    {
      int i = 0;
      int j = 0;
      int stop = 0;
      int alphabet_count = 0;
      int numbers_count = 0;
      char lower_case[27] = {'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'};
      char numbers[10] = {'0', '1', '2', '3', '4', '5', '6', '7', '8',
      '9'};
      char encrypted_string[5][6];
      for (j = 0; j < 5; j++)
      {
         for (i = 0; i < 5; i++)
         {
           alphabet_count = 0;
           numbers_count = 0;
           stop = 0;
           while (stop == 0)
           {
              if (login_ids[j][i] == lower_case[alphabet_count])
              {
                 encrypted_string[j][i] = ((((login_ids[j][i]-'a')+7)%26)+'a');
                stop = 1;
            }
            else if (login_ids[j][i] == numbers[numbers_count])
            {
                encrypted_string[j][i] = ((((login_ids[j][i] - '0')+7)%10)+'0');
                stop = 1;
            }
            else
            {
                alphabet_count++;
                numbers_count++;
            }
        }
    }
}
printf("debug : %s\n", encrypted_string[0]);
printf("debug : %s\n", encrypted_string[1]);
printf("debug : %s\n", encrypted_string[2]);
printf("debug : %s\n", encrypted_string[3]);
printf("debug : %s", encrypted_string[4]);
}

login_ids的内容是"vc136","jc580","cl274","tm361,"ns792" 将它们打印出来时,它们都很好地加密,除了麻烦的第三个 "cj803"、"qj257"、"js941^3at038"、"at038"、"uz469" 这是非常令人困惑的,因为位置 [2] 处的字符串超过 6 个字符,这是不应该的。 感谢任何和所有反馈,包括对我的代码有多糟糕的评论,或者这个问题是否以任何方式滥用网站。谢谢你。

#include <stdio.h>

void encryptIDS(char login_ids[5][6]);

int main(void) {
    char login_ids[5][6] = {{"vc136"},{"jc580"},{"cl274"},{"tm361"},{"ns792"}};
    encryptIDS(login_ids);
    return 0;
}



 void encryptIDS(char login_ids[5][6])
{
    int i = 0;
    int j = 0;
    int stop = 0;
    int alphabet_count = 0;
    int numbers_count = 0;
    char lower_case[27] = {'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'};
    char numbers[10] = {'0', '1', '2', '3', '4', '5', '6', '7', '8',
        '9'};
    char encrypted_string[5][6] = {0};
    for (j = 0; j < 5; j++)
    {
        for (i = 0; i < 5; i++)
        {
            alphabet_count = 0;
            numbers_count = 0;
            stop = 0;
            while (stop == 0)
            {
                if (login_ids[j][i] == lower_case[alphabet_count])
                {
                    encrypted_string[j][i] = ((((login_ids[j][i]-'a')+7)%26)+'a');
                    stop = 1;
                }

                if(numbers_count < 10)
                {
                    if (login_ids[j][i] == numbers[numbers_count])
                    {
                        encrypted_string[j][i] = ((((login_ids[j][i] - '0')+7)%10)+'0');
                        stop = 1;
                    }
                }

                alphabet_count++;
                numbers_count++;
            }
        }
    }
    printf("debug : %s\n", encrypted_string[0]);
    printf("debug : %s\n", encrypted_string[1]);
    printf("debug : %s\n", encrypted_string[2]);
    printf("debug : %s\n", encrypted_string[3]);
    printf("debug : %s", encrypted_string[4]);
}

输出

debug : cj803
debug : qj257
debug : js941
debug : at038
debug : uz469

问题出在数字索引上,当字母需要 10 多次迭代才能找到匹配项时。我重新安排了while循环逻辑来防止越界索引,这是你期待的结果吗?

编辑 我 copy/pasted 你的代码到 codechef 中。com/ide 来修复它,但我没有修复所有 formatting/indenting。您应该在下次发布之前自行修复格式(仅供回答您的人参考)。

不要生气,但是您的代码正如您所怀疑的那样糟糕:)

但是,这是一个了解原因以及如何修复它的机会,所以我将详细解释:

您的代码有 4 个主要问题。
其中两个会破坏程序,并会导致程序打印垃圾或因分段错误而崩溃,具体取决于程序运行时的内存布局。 其他两个让您的程序打印出正确的答案,但由于浪费内存和处理器周期而使其效率极低。
如果这是你要评分的作业,你会失去分数,如果你是自学,这是一种糟糕的编程习惯。

问题一:
正如评论中已经指出的那样,您必须始终以 NULL 终止 C 中的字符串。 如果你不这样做,像 printf 这样使用它们的函数将继续打印内存内容,直到它们遇到随机 NULL 值或直到你的程序崩溃。

所以,在你的外部 for 循环中,你必须添加这样一行:

for (j = 0; j < 5; i++) {
    //code to do the cypher

    encrypted_string[j][5] = '[=10=]'; //add terminator to string
}

或者,您可以按照 Bwebb 向您展示的方式初始化数组:

encrypted_string[5][6] = { '[=11=]' };

这将预先在所有数组单元格中置零。但是,如果您使用此方法,请注意不要覆盖其中一个循环中字符串的最后一个单元格![=2​​2=]

问题二:
Bwebb 还指出,您将 alphabet_countnumbers_count 一起递增,但使用 numbers_count 来索引较小的数组。

这意味着对于从 k 到 z 的任何字母,您的程序将访问它在执行第二次 if 检查时不应触及的内存。

但是,如果您解决以下两个问题并正确构建代码,此问题将自行消失。

问题三:
你用两个大数组浪费内存:字母数组和数字数组。
你不需要它们!既然你正确计算了密码,你肯定已经知道字母和数字在计算机中是如何表示的,所以你不需要将你的字符串与这些数组的内容一一比较。

你知道字母是一个连续的范围,所以只用一个 if.

问题四:
你在 while 循环上浪费了时间。
这是问题 3 中所述的同一问题的一部分 - 您不需要循环! 比较一次,看当前字符是否在字母范围内,如果不在,再比较一次,看是否在数字范围内。

如果您仅修复问题 1 和 2,您的代码将正常工作,但如果您修复问题 3 和 4,您的代码将更短且更易于阅读和理解,因此出现任何其他错误的可能性将大大降低英寸

操作方法如下:

//this is the inner loop, the outer loop over j stays the same
for (i = 0; i < 5; i++) {
    //check if this is a letter - a range between a and z inclusive:
    if (encrypted_string[j][i] >= 'a' && encrypted_string[j][i] <= 'z') {
        encrypted_string[j][i] += 7; //encrypt through shift by 7

        //rotate to beginning of alphabet if needed:
        if (encrypted_string[j][i] > 'z') encrypted_string[j][i] -= 26;
    } else if (/* do the same thing for numbers) {
        ...
    }
}

请注意,我将您的加密计算分为两行:这也是为了便于阅读和理解。

您仍然可以使用原来的计算:

encrypted_string[j][i] = ((((login_ids[j][i] - 'a') + 7) % 26) + 'a');

但是可读性是任何好的代码的一个重要方面。