CS50 Pset2-凯撒密码
CS50 Pset 2- ceasar cipher
它没有显示我想要它显示的是输入文本的加密版本,而是符号,我猜,看起来有点像“?”作为终端中的输出出现。谁能帮我找出我错过或做错了什么?
#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' 但事实并非如此。
此代码错误:
int key = (int) argv[1];
argv
是string
的数组,在CS50中无非是一个混淆的char *
指针。
根据 5.1.2.2.1 Program startup of the C standard:
The function called at program startup is named main. The implementation declares no prototype for this function. It shall be defined with a return type of int and with no parameters:
int main(void) { /* ... */ }
or with two parameters (referred to here as argc and argv, though any names may be used, as they are local to the function in which they are declared):
int main(int argc, char *argv[]) { /* ... */ }
or equivalent; ...
所以 argv[1]
是一个 char *
指针值,然后您将其分配给 int
值。这是获取一些内存的地址(比如 argv[1]
中的值是 0xFF0403220020480C
)并试图将其填充到 int
变量 key
的可能的 4 个字节中(在这种情况将被分配截断值 0x0020480C
。)
这不是你想要做的。
(IMO,你这里的问题是一个完美的例子,说明了为什么 CS50 将 char *
与 string
类型混淆是一个非常糟糕的主意。如果不理解指针和NUL
终止的 char
字符串通过 char *
指针访问,而 string
所做的混淆使得这更难。)
如果你想convert a string to a numeric value, you likely want something like strtol()
(never use atoi()
as it has no error checking and its use can invoke undefined behavior):
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 )
{
...
}
省略了适当的 headers,作为任何尝试使用此代码的人的练习 ;-)
请注意,我将 long
用于 key
,因为如果将 return 值转换为 [,则无法对 strtol()
进行完整和正确的错误检查=20=].
错误检查 strtol()
可能有点复杂,因为值 returned(并在上面的代码中分配给 key
)可以是任何值,并且没有可能的值不是合法的 long
值,strtol()
可以 return 指示错误,因此为了正确检查错误,您需要检查 errno
和 [=43= 的值] 以正确确定是否确实发生了错误。 Linux man page 状态:
Since strtol() can legitimately return 0, LONG_MAX, or LONG_MIN
(LLONG_MAX or LLONG_MIN for strtoll()) on both success and failure,
the calling program should set errno to 0 before the call, and then
determine if an error occurred by checking whether errno has a
nonzero value after the call.
调用 strtol()
后,您需要检查 key
是否为 LONG_MIN
,或者 LONG_MAX
且 errno
等于 ERANGE
下溢或溢出,或者如果 key
是 0
,您需要检查 firstCharNotConverted
的内容以确定转换失败的原因。请注意,如果 key
为零且 firstCharNotConverted
不等于 argv[ 1 ]
,则输入字符串已从零正确转换。
你的 Ceaser 密码实现也是错误的:
for (int i = 0, n = strlen(ptext); i < n; i++)
{
printf("%c", (( ptext[i] + key ) % 26);
}
printf("\n");
将只打印出值从 0
到 25
的字符 - 这些字符不是 ASCII 字符集中的字母。
这里已经发布了很多 Ceaser 密码问题,所以我不打算编写代码。参见 Caesar's Cipher Code 的一个示例问题。
问题就在这里printf("%c", (( ptext[i] + key ) % 26);
。特别是 % 26
。它看起来确实与问题集完全一样:
More formally, if p is some plaintext (i.e., an unencrypted message),
pi is the ith character in p, and k is a secret key (i.e., a
non-negative integer), then each letter, ci, in the ciphertext, c, is
computed as
ci = (pi + k) % 26
wherein % 26 here means “remainder when dividing by 26.”
但是,pset 继续说:
think of A (or a) as 0, B (or b) as 1, …, H (or h) as 7, I (or i) as
8, …, and Z (or z) as 25.
问题是字符 ptext[i]
是 ascii value of the letter,而不是 "alphabet index"。
也许查看实验室伪代码部分的剧透,尤其是 #5:
Iterate over each character of the plaintext:
- If it is an uppercase letter, rotate it, preserving case, then print out the rotated character
- If it is a lowercase letter, rotate it, preserving case, then print out the rotated character
- If it is neither, print out the character as is
您可能会发现此 walkthrough(来自课程的早期版本)很有帮助。
它没有显示我想要它显示的是输入文本的加密版本,而是符号,我猜,看起来有点像“?”作为终端中的输出出现。谁能帮我找出我错过或做错了什么?
#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' 但事实并非如此。
此代码错误:
int key = (int) argv[1];
argv
是string
的数组,在CS50中无非是一个混淆的char *
指针。
根据 5.1.2.2.1 Program startup of the C standard:
The function called at program startup is named main. The implementation declares no prototype for this function. It shall be defined with a return type of int and with no parameters:
int main(void) { /* ... */ }
or with two parameters (referred to here as argc and argv, though any names may be used, as they are local to the function in which they are declared):
int main(int argc, char *argv[]) { /* ... */ }
or equivalent; ...
所以 argv[1]
是一个 char *
指针值,然后您将其分配给 int
值。这是获取一些内存的地址(比如 argv[1]
中的值是 0xFF0403220020480C
)并试图将其填充到 int
变量 key
的可能的 4 个字节中(在这种情况将被分配截断值 0x0020480C
。)
这不是你想要做的。
(IMO,你这里的问题是一个完美的例子,说明了为什么 CS50 将 char *
与 string
类型混淆是一个非常糟糕的主意。如果不理解指针和NUL
终止的 char
字符串通过 char *
指针访问,而 string
所做的混淆使得这更难。)
如果你想convert a string to a numeric value, you likely want something like strtol()
(never use atoi()
as it has no error checking and its use can invoke undefined behavior):
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 )
{
...
}
省略了适当的 headers,作为任何尝试使用此代码的人的练习 ;-)
请注意,我将 long
用于 key
,因为如果将 return 值转换为 [,则无法对 strtol()
进行完整和正确的错误检查=20=].
错误检查 strtol()
可能有点复杂,因为值 returned(并在上面的代码中分配给 key
)可以是任何值,并且没有可能的值不是合法的 long
值,strtol()
可以 return 指示错误,因此为了正确检查错误,您需要检查 errno
和 [=43= 的值] 以正确确定是否确实发生了错误。 Linux man page 状态:
Since strtol() can legitimately return 0, LONG_MAX, or LONG_MIN (LLONG_MAX or LLONG_MIN for strtoll()) on both success and failure, the calling program should set errno to 0 before the call, and then determine if an error occurred by checking whether errno has a nonzero value after the call.
调用 strtol()
后,您需要检查 key
是否为 LONG_MIN
,或者 LONG_MAX
且 errno
等于 ERANGE
下溢或溢出,或者如果 key
是 0
,您需要检查 firstCharNotConverted
的内容以确定转换失败的原因。请注意,如果 key
为零且 firstCharNotConverted
不等于 argv[ 1 ]
,则输入字符串已从零正确转换。
你的 Ceaser 密码实现也是错误的:
for (int i = 0, n = strlen(ptext); i < n; i++)
{
printf("%c", (( ptext[i] + key ) % 26);
}
printf("\n");
将只打印出值从 0
到 25
的字符 - 这些字符不是 ASCII 字符集中的字母。
这里已经发布了很多 Ceaser 密码问题,所以我不打算编写代码。参见 Caesar's Cipher Code 的一个示例问题。
问题就在这里printf("%c", (( ptext[i] + key ) % 26);
。特别是 % 26
。它看起来确实与问题集完全一样:
More formally, if p is some plaintext (i.e., an unencrypted message), pi is the ith character in p, and k is a secret key (i.e., a non-negative integer), then each letter, ci, in the ciphertext, c, is computed as
ci = (pi + k) % 26
wherein % 26 here means “remainder when dividing by 26.”
但是,pset 继续说:
think of A (or a) as 0, B (or b) as 1, …, H (or h) as 7, I (or i) as 8, …, and Z (or z) as 25.
问题是字符 ptext[i]
是 ascii value of the letter,而不是 "alphabet index"。
也许查看实验室伪代码部分的剧透,尤其是 #5:
Iterate over each character of the plaintext:
- If it is an uppercase letter, rotate it, preserving case, then print out the rotated character
- If it is a lowercase letter, rotate it, preserving case, then print out the rotated character
- If it is neither, print out the character as is
您可能会发现此 walkthrough(来自课程的早期版本)很有帮助。