凯撒密码在C语言中的数字实现

3
我想制作一个数字凯撒密码。(所有数字加3)
输入: 52 输出: 85
输入: 954 输出: 287
输入: -10457 输出: -43780
如果有人能帮助我,我会非常高兴。
我尝试过这个程序,但当我输入少于5位数的数字时,它会在开头输出3。
当我输入52时,它输出33385。我还想问用户程序是否应接受新数字或退出。
#include <stdio.h>
#include <stdlib.h>

int main()
{

    int number, operation;

    printf("Enter the number: ");
    scanf("%d", &number);

    printf("%d", ((number / 10000) + 3) % 10);
    printf("%d", (((number % 10000) / 1000) + 3) % 10);
    printf("%d", (((number % 1000) / 100) + 3) % 10);
    printf("%d", (((number % 100) / 10) + 3) % 10);
    printf("%d\n", ((number % 10) + 3) % 10);

    printf("press 1 to continue or 2 for exit.");
    scanf("%d", &operation);

    switch (operation) {
    case 1:
        printf("Enter the number: ");
        scanf("%d", &number);

        printf("%d", ((number / 10000) + 3) % 10);
        printf("%d", (((number % 10000) / 1000) + 3) % 10);
        printf("%d", (((number % 1000) / 100) + 3) % 10);
        printf("%d", (((number % 100) / 10) + 3) % 10);
        printf("%d\n", ((number % 10) + 3) % 10);

        break;

    case 2:

        break;
    }

    return 0;
}

你认为777会打印出什么:0还是000? - chux - Reinstate Monica
3个回答

5
当您输入52时,您的数字变量将取值00052,这将在您的代码中转换为33385。如果您不想要前导3,则可以不打印它们,或者先检索数字并仅在该数字不为0时计算其关联的凯撒数字。
考虑另一种可能性,即考虑任何int数字(无论数字有多少位):
#include "stdio.h"
#include <stdlib.h>

int main()
{
    int number, abs_number;
    int caesar_number = 0;
    int digit_pos = 1;

    printf("Enter the number: ");
    scanf("%d", &number);

    abs_number = abs(number);

    while (abs_number != 0)
    {
        caesar_number += (((abs_number % 10) + 3) % 10) * digit_pos;
        abs_number /= 10;
        digit_pos *= 10;
    }

    if (number < 0)
    {
        caesar_number = -caesar_number;
    }
    printf("Result is: %d\n", caesar_number);

    return 0;
}

2
这个解决方案适用于所有测试用例(包括正数和负数),适用于大于100000的数字,也适用于零:
#include "stdio.h"
#include "stdlib.h"

const int SHIFT = 3;

int main() {
    int number, abs_number, is_negative, operation, result, decimal_place;

    do {
        result = 0;
        decimal_place = 1;

        printf("Enter the number: ");
        scanf("%d", &number);

        // remove the sign before entering the cipher logic...
        abs_number = abs(number);
        // ...but do remember it so we can add it back later
        is_negative = number < 0;

        // from least to most significant decimal place
        do {
            // cipher the digit and accumulate it in the result
            result += (((abs_number % 10) + SHIFT) % 10) * decimal_place;
            // remove the consumed digit from the input variable
            abs_number /= 10;
            // move to the next decimal place
            decimal_place *= 10;
        } while (abs_number > 0);

        printf("Result is: %s%d\n", is_negative ? "-" : "", result);

        printf("Press 1 to continue or 2 for exit.");
        scanf("%d", &operation);

    } while (operation == 1);  // repeat if user requested another cipher

    return 0;
}

在原始代码中需要注意以下几点:

  • 您的代码没有循环。 switch 语句不能帮助您重复操作。您需要使用 while 循环来实现;
  • 它无法处理较大的数字:您需要添加一行额外的代码来处理大于100000的数字...这导致了我的下一个观点:
  • 您有重复的代码:您的逻辑以两种不同的方式重复。第一种是迭代体。即使您用 while 循环替换了 switch 语句,您的第一个迭代在循环外部不必要地展开。第二种是您处理输入数字的每个小数位的方式。如果您有相同的代码片段来处理任何小数位,那么会更好吗?复制代码被认为是不良实践。它使代码变得更大,更难维护,并且易于在一个地方更改重复的代码而在另一个地方不更改。您总是想避免复制代码。

1
除非记录用户输入的长度,“凯撒密码数字版”是不可逆的。对于像"777""7""000""0"这样的输入,输出需要4个不同的答案才能进行转换回来。
为了保持一定的数字内部表示,考虑使用"%n"来跟踪用户输入的长度。
static void print_digits(int a, int length, int offset) {
  if (length > 1) {
    print_digits(a/10, length-1);
  }
  putchar((a+offset)%10 + '0');
}

...

#define OFFSET 3

int number;
int n1, n2;
int offset = OFFSET % 10;
if (offset < 10) offset += 10; // Handle negative OFFSET

printf("Enter the number: ");
if (scanf(" %n%d%n", &n1, &number, &n2) == 1) {
  int length = n2 - n1;
  if (number < 0) {
    putchar('-');
    number = -number;
    length--;
  }
  print_digits(number, length, offset);
}

以上代码在选择输入量大于INT_MAX/10左右时存在问题。为了处理大整数,请考虑转换为字符串处理。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接