首先,没有人可以提出这样的问题所以请原谅我
#include <stdio.h>
#include <cs50.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main(int argc, string argv[]) {
string key = argv[1];
int l = strlen(argv[1]);
if (argc != 2) {
return 0;
}
for (int i = 0, n = strlen(key); i < n; i++) {
if (!isalpha(key[i])) {
return 0;
}
key[i] = tolower(key[i]);
key[i] = key[i] - 97;
}
string txt = GetString();
for (int k = 0, p = strlen(txt); k < p; k++) {
if (isalpha(txt[k])) {
if (isupper(txt[k])) {
printf("%c", (((txt[k] - 65) + (key[k % l])) % 26 + 65));
}
if (islower(txt[k])) {
printf("%c", (((txt[k] - 97) + (key[k % l])) % 26 + 97));
}
} else
if (!isalpha(txt[k])) {
printf("%c", txt[k]);
}
}
printf("\n");
return 0;
}
我无法获得这两行代码
key[i] = key[i] - 97;
printf("%c", (((txt[k] - 97) + (key[k % l])) % 26 + 97));
是否有一个简单的解释,为什么我们使用第一个以及第二个如何工作?
答案 0 :(得分:1)
用于Vigenere cypher的密钥应该是所有字母。第一个表达式将字符串转换为偏移数组,0
为a
,1
为b
等.97是'a'
的ASCII代码。写起来会更具可读性:
for (int i = 0, n = strlen(key); i < n; i++) {
if (!isalpha((unsigned char)key[i])) {
printf("key '%s' must contain only letters\n", key);
return 1;
}
key[i] = tolower((unsigned char)key[i]);
key[i] = key[i] - 'a';
}
对于第二个表达式,如果字符txt[k]
是小写字母,printf("%c", (((txt[k] - 97) + (key[k % l])) % 26 + 97));
计算并通过添加移位值打印转置字母(key
中的每个字符用作一个接一个的移位值,移0
a
,1
换b
等。以下是步骤:
txt[k] - 97
,97
是'a'
的ASCII代码,key[k % l]
,以循环方式循环key
中的值,97
,ASCII值为'a'
,将索引转换回小写字母。以这种方式编写它会减少冗余和可读性:
for (int i = 0, j = 0; txt[i] != '\0'; i++) {
int c = (unsigned char)txt[i];
if (isupper(c)) {
c = (c - 'A' + key[j++ % l]) % 26 + 'A';
} else
if (islower(c)) {
c = (c - 'a' + key[j++ % l]) % 26 + 'a';
}
putchar(c);
}
另请注意,在检查命令行上是否传递了足够的参数之前,不应将argv[1]
传递给strlen()
。
以下是该程序的修改版本:
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, string argv[]) {
if (argc != 2) {
printf("missing key argument\n");
return 1;
}
string key = argv[1];
int klen = strlen(key);
if (klen == 0) {
printf("key cannot be empty\n");
return 1;
}
for (int i = 0; i < klen; i++) {
if (!isalpha((unsigned char)key[i])) {
printf("key '%s' must contain only letters\n", key);
return 1;
}
key[i] = tolower((unsigned char)key[i]) - 'a';
}
string txt = GetString();
for (int i = 0, j = 0; txt[i] != '\0'; i++) {
int c = (unsigned char)txt[i];
if (isupper(c)) {
c = (c - 'A' + key[j++ % klen]) % 26 + 'A';
} else
if (islower(c)) {
c = (c - 'a' + key[j++ % klen]) % 26 + 'a';
}
putchar(c);
}
putchar('\n');
return 0;
}
答案 1 :(得分:0)
key[i] = key[i] - 97;
该行的用法是给key [i],该值表示ascii中的字符值,它是我们字母表中的索引。然后,&#39; a&#39;将被赋予值0,&#39; b&#39;值1 ....,&#39; z&#39;价值25。
至于第二行,
printf("%c", (((txt[k] - 97) + (key[k % l])) % 26 + 97))
打印出ascii值为
的字符(((txt[k] - 97) + (key[k % l])) % 26 + 97))
97的减法具有与上述相同的目的。
%26是模数,即每26分(整数除)时((txt [k] -97)+(键[k%l]))的余数。然后,再次添加97以将结果的顺序或索引转换为相应的ascii值。 此页面可能会让您更深入地了解C中的字符表示。
至于k,i和l的含义,我让你自己掌握了密码的内在功能,但整个加密发生在你想要解释的第二行。
PS:带有&#39; 65&#39;的零件是一样的,但用大写字母,因为&#39; A&#39; ascii中的值是65。