它没有显示我想要显示的是输入文本的加密版本,而是符号,正如我猜想的那样,看起来有点像“?”在终端输出。谁能帮我找到我错过或做错的事吗?
#include <cs50.h>
#include <stdio.h>
#include <string.h>
int main(int argc, string argv[])
{
if (argc == 2)
{
string ptext = get_string("plaintext: ");
int key = (int) argv[1];
printf("ciphertext: ");
for (int i = 0, n = strlen(ptext); i < n; i++)
{
printf("%c", (( ptext[i] + key ) % 26);
}
printf("\n");
}
else
{
printf("Invalid input. \n");
}
}
我希望'hello'的输出为'ifmmp',但实际上不是。
答案 0 :(得分:0)
此代码是错误的:
int key = (int) argv[1];
argv
是string
的数组,在CS50中仅是模糊的char *
指针。
每5.1.2.2.1 Program startup of the C standard:
在程序启动时调用的函数称为main。该实现没有为此函数声明任何原型。它应使用返回类型int且没有参数来定义:
int main(void) { /* ... */ }
或具有两个参数(尽管可以使用任何名称,但在此处称为argc和argv,因为它们是声明它们的函数的局部名称):
int main(int argc, char *argv[]) { /* ... */ }
或同等学历; ...
因此argv[1]
是一个char *
指针值,然后将其分配给一个int
值。那会占用一些内存的地址(例如argv[1]
中的值为0xFF0403220020480C
),并试图将其填充到int
变量key
的可能4个字节中(这种情况下将被赋予截断值0x0020480C
。)
这似乎不是您想要做的。
(IMO,您的问题是一个很好的例子,说明为什么CS50对char *
类型的string
进行混淆是一个非常糟糕的主意。如果不理解指针和{{ 1}}终止的NUL
字符串可通过char
指针访问,而char *
的混淆使之变得更加困难。)
如果您想convert a string to a numeric value,则可能需要something like strtol()
(never use atoi()
as it has no error checking and its use can invoke undefined behavior):
string
对于尝试使用此代码的任何人,练习都省略适当的标题;-)
请注意,我将char firstCharNotConverted;
// set errno to zero as strtol()
errno = 0;
long key = strtol( argv[ 1 ], &firstCharNotConverted, 0 );
// if errno is now non-zero, the call to strtol() failed (per Linux man page)
// need to examine key and the contents of firstCharNotConverted
// to figure out why
if ( errno != 0 )
{
...
}
用于long
,因为如果将返回值强制转换为key
,则无法对strtol()
进行正确的错误检查。 / p>
错误检查int
可能会有些复杂,因为返回的值(并在上面的代码中分配给strtol()
)可以是任何值,并且不可能存在不合法的值{{1 key
可以返回的}}值表示错误,因此要进行正确的错误检查,您需要检查long
和strtol()
的值以正确确定是否确实发生了错误。 Linux man page指出:
由于strtol()可以合法地返回0,LONG_MAX或LONG_MIN (对于strtoll()为LLONG_MAX或LLONG_MIN)是否成功, 调用程序应在调用之前将errno设置为0,然后 通过检查errno是否具有一个错误来确定是否发生了错误 通话后返回非零值。
在调用errno
之后,您需要检查firstCharNotConverted
是strtol()
还是key
的{{1}}等于LONG_MIN
下溢或上溢,或者如果LONG_MAX
是errno
,则需要检查ERANGE
的内容,以确定转换失败的原因。请注意,如果key
为零,并且0
不等于firstCharNotConverted
,则输入字符串已从零正确转换。
您的Ceaser密码实现也不正确:
key
只会打印出从firstCharNotConverted
到argv[ 1 ]
之间的值的字符-在ASCII字符集中不是字母。
这里已经发布了许多Ceaser密码问题,因此我不会编写代码。有关一个示例问题,请参见Caesar's Cipher Code。
答案 1 :(得分:0)
问题出在这里printf("%c", (( ptext[i] + key ) % 26);
。特别是% 26
。它肯定看起来像问题集:
更正式地说,如果p是一些纯文本(即未加密的消息), pi是p中的第i个字符,k是密钥(即,a 非负整数),则密文c中的每个字母ci为 计算为
ci =(pi + k)%26
其中%26在这里表示“除以26所得的余数。”
但是,pset继续说:
认为A(或a)为0,B(或b)为1,…,H(或h)为7,I(或i)为 8,…,Z(或z)为25。
问题在于字符ptext[i]
是ascii value of the letter,而不是“字母索引”。
也许可以在实验室的伪代码部分中查看扰流板,尤其是#5:
遍历明文的每个字符:
- 如果是大写字母,请将其旋转,保留大小写,然后打印出旋转的字符
- 如果是小写字母,请将其旋转,保留大小写,然后打印出旋转的字符
- 如果都不是,则按原样打印字符
您可能会发现walkthrough(来自课程的早期迭代)很有帮助。