Warm tip: This article is reproduced from serverfault.com, please click

c-循环ASCII字符并解密消息

(c - Looping ASCII characters and decrypting the message)

发布于 2020-12-05 07:57:08

我的老师给我做作业:-

系统会为你提供一个字符串(最多100个字符),该字符串由小写字符组成,并以#符号结尾。该字符串是原始字符串的“加密”形式,如下所示-原始字符串中的每个字符已移位固定整数n(其中1 <= n <= 25)。

假设a是字母中的第0个字符,...,z是字母中的第25个字符,在加密版本中,我们有:

'a'成为字母表中的第n个字符,'b'成为字母表中的第(n + 1)%26个字符,...

等等。

n不为你所知。你只知道第一个字符代表“ t”。根据此信息,你必须输出原始字符串。

这是我的代码:-

#include <stdio.h>
#include <stdlib.h>

int main()
{
    char array[100]; //string will be stored here.
    char a;
    int i = 0; //initializer
    
    scanf("%c", &a);
    
    int counter = 0; // to count the size of the string
    
    while(a != '#')
    {
        array[i] = a;
        i++;
        counter++;
        scanf("%c", &a);
    }
    
    a = 't';
    
    int temp = a - array[0]; //To get the offset of the encrypted message.
    
    for(i = 0; i < counter; i++)
    {
        if((array[i] + temp) >= 'a' && (array[i] + temp) <= 'z')
        {
            array[i] = array[i] + temp; //Applying the offset to the encrypted message to get the true message.
        }
        
        else if((array[i] + temp) < 'a')
        {
            array[i] = 'z' - (temp - (array[i] - 'a')); //If offset is large and it falls below ASCII charater number 'a' then loop back to 'z'.
        }
        
        else
        {
            array[i] = 'a' + (temp - ('z' - array[i])); //If offset is large and it falls above ASCII charater number 'z' then loop back to 'a'.
        }
    }
    
    puts(array);
    
    return 0;
}

现在,我所采用的逻辑肯定是错误的。我所有的测试用例都失败了。我怀疑问题出在以下代码片段中:-

for(i = 0; i < counter; i++)
    {
        if((array[i] + temp) >= 'a' && (array[i] + temp) <= 'z')
        {
            array[i] = array[i] + temp; //Applying the offset to the encrypted message to get the true message.
        }
        
        else if((array[i] + temp) < 'a')
        {
            array[i] = 'z' - (temp - (array[i] - 'a')); //If offset is large and it falls below ASCII charater number 'a' then loop back to 'z'.
        }
        
        else
        {
            array[i] = 'a' + (temp - ('z' - array[i])); //If offset is large and it falls above ASCII charater number 'z' then loop back to 'a'.
        }
    }

我不能做这个简单的问题。请帮忙。

下面提到了一些测试用例:-

测试用例

Questioner
Swarnim Khosla
Viewed
0
OctaveL 2020-12-05 20:41:44
#include <stdio.h>
#include <stdlib.h>

int main()
{
    char array[100]; //string will be stored here.
    int counter = 0; // to count the size of the string

    scanf("%s", array);

    while(array[counter] != '#')
        counter++;

    int offset = 't' - array[0]; //To get the offset of the encrypted message.

    if (offset < 0)
        offset = 26 + offset;

    for(int i = 0; i < counter; i++)
        array[i] = ((array[i] - 'a' + offset) % 26) + 'a';

    array[counter] = '\0'; // Removing the # at the end

    puts(array);

    return 0;
}

第一,终止字符串不是空值,因此有时会在末尾添加多余的字符。我通过询问一个字符串而不是连续几个字符来解决它,我个人发现这要简单得多。然后\0,它会自动在数组的末尾添加a ,而不是逐个字符地添加。话虽如此,你的人也可以使用,但前提是你必须array[counter] = '\0'在结尾处添加a来将其终止。

'a'成为字母表中的第n个字符,'b'成为字母表中的第(n + 1)%26个字符,...

你的实现非常复杂。array[i] = ((array[i] - 'a' + offset) % 26) + 'a';这里只需要一行即可

为了进行分解,我们通过执行以下操作获得字母在字母表中的索引array[i] - 'a'我们添加偏移量,然后以26为模(字母中的字符数)以获取新字母的索引,并考虑到我们可以得到高于26的结果(在这种情况下,我们希望回绕) :29表示字母表的第三个字母,因为29-26 = 3)。我们加回来'a'得到一个实际的字符而不是一个索引,并且我们得到了正确的字母。

另外,你的代码当前容易受到缓冲区溢出的影响!你不应该太在意学校的项目,但这是你可能有兴趣了解更多信息的巨大的安全漏洞。如果输入字符串中没有#,那么你也很容易出现分段错误。

由于这是学校项目,因此我故意没有对你的代码进行太多改进,但是知道该变量counter完全不必要,因此你可以重新设计代码以避免使用它。你可能需要考虑如何进行此操作。