我正在尝试自己为 cs50 的实验室作业实现凯撒加密。我完成了它,但是当我使用 do-while 循环来确定“旋转”函数中键的范围时,我的程序无法按预期工作,但是当我使用模来确定键时,程序可以工作。但我无法说出有什么区别。两者(do while 和模运算符)应该以相同的方式产生结果。你能告诉我,以便我能够理解并继续处理这个问题吗?
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
bool only_digits(string s);
char rotate(char c, int k);
int main(int argc, string argv[])
{
if (argc <= 1 || argc > 2)
{
printf("Usage: ./caesar key\n");
return 1;
}
//check if only digits
if (only_digits(argv[1]))
{
printf("Usage: ./caesar key\n");
return 1;
}
int k = atoi(argv[1]);
string e = get_string("plaintext: ");
int length = strlen(e);
for (int t = 0; t < length; t++)
{
e[t] = rotate(e[t], k);
}
printf("%s\n", e);
}
char rotate(char c, int k)
{
//key loop length
do
{
k -= 26;
}
while(k > 25);
//Uppercase encryption
if (c >= 65 && c <= 90)
{
c += k;
if (c > 90)
{
c -= 26;
}
}
//Lowercase encrypt
if (c >= 97 && c <= 122)
{
c += k;
if (c > 122)
{
c -= 26;
}
}
return c;
}
bool only_digits(string s)
{
int u = strlen(s);
int i;
for (i = 0; i < u; i++)
{
if (!isdigit(s[i]))
{
return true;
}
}
return false;
}
do
-while
是循环体上的迭代语句。 %
(模)是一个运算符。
argc <= 1 || argc > 2
更好地表达为 argc != 2
。
考虑使用更具描述性的错误消息。在第一种情况下,您缺少参数,而在第二种情况下,键不是数字。
atoi()
没有表达错误的方法。首先考虑使用 only_digits()
,而不是自己进行 strtol()
检查。
only_digits()
应该检查是否只包含数字。对我来说,如果确实如此,您返回 false 会令人困惑。要么将函数重命名为 any_non_digits()
,要么在函数和使用中否定结果。
only_digits()
:更喜欢循环局部变量:
for (int i = 0; i < u; i++)
对于字符串,终止符是
\0
是 false,所以你通常这样写:
bool only_digits(string s) {
if(!s) return false;
while(*s)
if(!isdigit(*s++) return true;
return false;
}
isdigit()
期望得到 int
,但你传递了 char
。
main(): int length = strlen(e)
:strlen()
返回size_t
,所以更喜欢使用它而不是int
。这也将鼓励您使用 size_t
为您提供 t
循环变量。
main()
:t
很好,但我们通常期望一些对使用有意义的东西或i
,j
,k
等
main()
:您在循环中调用rotate()
,这暗示也许它应该旋转整个字符串而不仅仅是一个字符。
rotate(): @WheaterVane provided a great solution on how to avoid the loop in
旋转()`,其中:
k = (k + 26) % 26
也就是说,也许您应该验证
k
中的 main()
是否介于 0 到 26 之间?
rotate()
:使用字符常量而不是 ascii 值。所以用“A”代替 65,用“Z”代替 90。
rotate()
:对于大写和小写,您执行两次非常相似的逻辑。考虑将字符转换为大写进行测试,这样您只需要做一次:
if(toupper(c) >= 'A' 7& toupper(c) <= 'Z') {
// ...
唯一的区别是现在进行了上部更改检查。
rotate()
:char c
是定义的实现,如果char
是signed
或unsigned
。如果它是 signed
(因为它在我的系统上),则 c = 'w
和 k = 10
操作 c += k
会导致溢出并变为负值。