CS50 凯撒密码漏洞
CS50 Caesar Cipher Bug
好吧,我完全被难住了。我不明白为什么这个程序输出每次都好像有一个随机密钥。
这个节目:
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, string argv[])
{
string sKey = argv[1];
// Make sure program was run with just one command-line argument
if (argc != 2 || atoi(argv[1]) < 0)
{
printf("Usage: ./caesar key\n");
return 1;
}
//Counts length of string and checks if all chars are digits
int counter = 0;
for (int i = 0; i < strlen(sKey); i++)
{
if isdigit(sKey[i])
{
counter++;
}
}
//Checks if the key is a number
if (counter != strlen(sKey))
{
printf("Usage: ./caesar key\n");
return 1;
}
// Convert argv[1] from a `string` to an `int`
int key = (int)sKey;
// Prompt user for plaintext
string plaintext = get_string("Plaintext: ");
printf("Ciphertext: ");
for (int i = 0; i < strlen(plaintext); i++)
{
if (isalpha(plaintext[i]) && isupper(plaintext[i]))
{
printf("%c", (((plaintext[i] - 'A') + key) % 26) + 'A');
}
else if (isalpha(plaintext[i]) && islower(plaintext[i]))
{
printf("%c", (((plaintext[i] - 'a') + key) % 26) + 'a');
}
else
{
printf("%c", plaintext[i]);
}
}
printf("\n");
}
将输出:
caesar/ $ ./caesar 1
Plaintext: Hello, I'm Justin.
Ciphertext: Fcjjm, G'k Hsqrgl.
caesar/ $ ./caesar 1
Plaintext: Hello, I'm Justin.
Ciphertext: Pmttw, Q'u Rcabqv.
这似乎是模运算符的问题,因为当我隔离它时我可以重现问题。它是我包含的库之一吗?我自己解决了这个问题,最后在 youtube 上查找了一个解决方案,结果发现我的解决方案执行了与正确解决方案相同的操作。我一定是遗漏了什么。
谢谢
这是因为 int key = (int)sKey;
不会将字符串转换为整数...至少不是您认为的那样。它将字符串指针 sKey
(内存地址)指向一个整数。因为每次你 运行 程序都可以是不同的地址,这就是它看起来随机的原因。将数字字符串转换为值的正确方法是使用 atoi
或 strtol
。你的程序的第一部分应该是这样的:
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, string argv[])
{
string sKey = argv[1];
int i;
// Make sure program was run with just one command-line argument
if (argc != 2)
{
printf("Usage: ./caesar key\n");
return 1;
}
// Checks if all chars are digits
for (int i = 0; sKey[i]; i++)
if (!isdigit(sKey[i]) break;
// If the key contains any non-digits, error
if (sKey[i])
{
printf("Usage: ./caesar key\n");
return 1;
}
// Convert argv[1] from a `string` to an `int`
int key = atoi(sKey);
// The rest should be fine
好吧,我完全被难住了。我不明白为什么这个程序输出每次都好像有一个随机密钥。
这个节目:
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, string argv[])
{
string sKey = argv[1];
// Make sure program was run with just one command-line argument
if (argc != 2 || atoi(argv[1]) < 0)
{
printf("Usage: ./caesar key\n");
return 1;
}
//Counts length of string and checks if all chars are digits
int counter = 0;
for (int i = 0; i < strlen(sKey); i++)
{
if isdigit(sKey[i])
{
counter++;
}
}
//Checks if the key is a number
if (counter != strlen(sKey))
{
printf("Usage: ./caesar key\n");
return 1;
}
// Convert argv[1] from a `string` to an `int`
int key = (int)sKey;
// Prompt user for plaintext
string plaintext = get_string("Plaintext: ");
printf("Ciphertext: ");
for (int i = 0; i < strlen(plaintext); i++)
{
if (isalpha(plaintext[i]) && isupper(plaintext[i]))
{
printf("%c", (((plaintext[i] - 'A') + key) % 26) + 'A');
}
else if (isalpha(plaintext[i]) && islower(plaintext[i]))
{
printf("%c", (((plaintext[i] - 'a') + key) % 26) + 'a');
}
else
{
printf("%c", plaintext[i]);
}
}
printf("\n");
}
将输出:
caesar/ $ ./caesar 1
Plaintext: Hello, I'm Justin.
Ciphertext: Fcjjm, G'k Hsqrgl.
caesar/ $ ./caesar 1
Plaintext: Hello, I'm Justin.
Ciphertext: Pmttw, Q'u Rcabqv.
这似乎是模运算符的问题,因为当我隔离它时我可以重现问题。它是我包含的库之一吗?我自己解决了这个问题,最后在 youtube 上查找了一个解决方案,结果发现我的解决方案执行了与正确解决方案相同的操作。我一定是遗漏了什么。
谢谢
这是因为 int key = (int)sKey;
不会将字符串转换为整数...至少不是您认为的那样。它将字符串指针 sKey
(内存地址)指向一个整数。因为每次你 运行 程序都可以是不同的地址,这就是它看起来随机的原因。将数字字符串转换为值的正确方法是使用 atoi
或 strtol
。你的程序的第一部分应该是这样的:
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, string argv[])
{
string sKey = argv[1];
int i;
// Make sure program was run with just one command-line argument
if (argc != 2)
{
printf("Usage: ./caesar key\n");
return 1;
}
// Checks if all chars are digits
for (int i = 0; sKey[i]; i++)
if (!isdigit(sKey[i]) break;
// If the key contains any non-digits, error
if (sKey[i])
{
printf("Usage: ./caesar key\n");
return 1;
}
// Convert argv[1] from a `string` to an `int`
int key = atoi(sKey);
// The rest should be fine