为什么我的密文得到负值?

时间:2019-08-09 13:42:00

标签: c cs50 caesar-cipher

这是CS50x设置的问题。这是凯撒密码。它需要通过在运行时输入的键来移动所有字母(大写和小写)。它应该保留大小写,符号和数字。

我认为代码是正确的,但是对于较大的键值,我一直得到ASCII负值。在纸上/数学上,它不应给出负值。我有些不懂的东西。

// Caesar cipher//
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

//cipher key//
int K[];

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

//checking for only one command-line argument//
    if(argc == 2)
    {

        //checking if key is digit//
          for(int i = 0, n=strlen(argv[1]); i < n; i++)
          {
              K[i] = (argv[1][i]-'0');
              if((K[i] < 0) || (K[i] > 9 ))
            {
                printf("Usage: ./caesar key\n");
                return 1;
                break;
            }
          }


          string p = get_string("plaintext: ");
          printf("ciphertext: ");
          char c[strlen(p)];
          for(int i = 0, n = strlen(p); i < n; i++)
          {

              if(((p[i] > 64) && (p[i] < 91)) || ((p[i] > 96) && (p[i] < 123)))
              {

                 int k = atoi(argv[1]);

                 c[i] = (p[i]+(k % 26));



                 if (c[i] > 122)
                 {
                     c[i] =  (c[i] % 122) + 96;
                 }

                 else if ((c[i] > 90) && (c[i] < 97))
                 {
                     c[i] = (c[i] % 90) + 64;
                 }


                 else
                 {
                     c[i] =  c[i];
                 }
              }
              else
              {
               c[i] = p[i];
              }
             printf("%c",c[i]);
          }

          printf("\n");

    }

    else
    {
      printf("Usage: ./caesar key\n");
      return 1;
    }


}

例如,键100和明文“ z”应给我一个118(v)值,但我得到-112(ASCII中不存在)。

2 个答案:

答案 0 :(得分:1)

数学都是错误的,并且您的负值是由于将超出范围的值分配给类型为char的数组元素而产生的。

假设您要通过用户指定的键值p[i]旋转存储在k中的大写拉丁字母,其范围为0 ... 25,并且您愿意假定该大写拉丁字母被编码为连续的,按字母顺序排列的值(因为它们采用ASCII格式,但不采用某些其他编码),计算将采用以下形式:

c[i] = (((p[i] - 'A') + k) % 26) + 'A';

最初减去'A'的值将产生0 ... 25范围内的结果(取决于上面给出的假设)。通过在该范围内进行轮换,可以通过添加键值并减少模26的总和来实现。最后,添加'A'可以将轮换后的结果返回到大写拉丁字母的范围内。这种方法或与其等效的方法是您进行求和模样式旋转所需要的,而问题程序中的数学是 not 等效的。

请注意,再次遵循指定的假设,任何中间结果甚至都不会超出类型char的范围(在这种情况下不直接相关),实际分配的任何此类值都更少到一个char变量(与相关和重要的变量)。

小写字母的计算是类似的(在类似的假设下),但不完全相同。

答案 1 :(得分:1)

错误是因为char已在C实现中并在此行中签名:

c[i] = (p[i]+(k % 26));

p[i] + k % 26(不需要括号)超过127时,结果不适合您的实现中的char,并且以实现定义的方式将其转换为char ,可能是通过对256模进行包装(等效地,使用低8位)。因此,在键值为100且字符'z'的值为122的情况下,结果为122 + 100%26 = 122 + 22 + 144,该结果存储在c[i]中为-112。

可以通过以下方法轻松解决:

char c[strlen(p)];

收件人:

unsigned char c[strlen(p)];