我的老师给我做作业:-
系统会为你提供一个字符串(最多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'.
}
}
我不能做这个简单的问题。请帮忙。
下面提到了一些测试用例:-
#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
完全不必要,因此你可以重新设计代码以避免使用它。你可能需要考虑如何进行此操作。
“您的实现非常复杂。” 好吧,那我们来看一下。绝对没有理由复制任何东西,或两次遍历字符串,或使用模。您可以在第一时间就地进行替换。
@OctaveL非常感谢您的深刻见解。现在,我已经能够理解所有内容。但是,我仍然无法理解您是如何仅使用1行来取出偏移量的
(int offset = ('t' + array[0] - 'a' * 2) % 26;)
。如果可能的话,请也解释一下。@Cheatah如果您认为自己能够提供比上述提到的答案更简单的答案,请务必发布。
@Cheatah我同意这不是最好的方法,但是我认为这是因为我尝试不对代码进行过多调整。例如,我很清楚计算
counter
是不必要的,但是我保留了它,因为这是Swarnim选择实现它的方式。我承认我应该更清楚一点,但是我不愿意提供更好的解决方案,因为这是一个学校项目,其中复杂的代码会脱颖而出,使OP似乎得到了答案。我很好奇为什么不需要模数;我考虑过一种不使用它的解决方案,但是我更喜欢它,正如作业中提到的那样。@SwarnimKhosla关于那条线;很抱歉,我将其从帖子中删除了,因为它是无效的,或者仅在75%的可能补偿中起作用。我坚信不使用三元运算符就可以在一行中执行(您可能在这里很好使用),但是我必须找到一个比这更好的公式。对不起,我很困惑。