Вот модифицированная версия вашего кода с изменениями, основанными на моих комментариях:
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int shift(char key1);
int main(int argc, string argv[]) // user enter number at cmd prompt
{
if (argc != 2 || argv[1][0] == '\0')
{
fprintf(stderr, "Usage: ./vigenere keyword\n");
return 1;
}
string key = argv[1]; // declare second arg as string
for (int i = 0, n = strlen(key); i < n; i++)
{
if (!isalpha(key[i]))
{
fprintf(stderr, "Usage: ./vigenere keyword\n");
return 1;
}
}
string text = get_string("plain text: ");
printf("ciphertext: ");
int keylen = strlen(key);
int keyidx = 0;
for (int j = 0, o = strlen(text); j < o; j++)
{
int t = text[j];
if (isupper(t))
{
int k = shift(key[keyidx++ % keylen]);
t += k;
if (t > 'Z')
t -= 26;
}
else if (islower(t))
{
int k = shift(key[keyidx++ % keylen]);
t += k;
if (t > 'z')
t -= 26;
}
printf("%c", t);
}
printf("\n");
}
int shift(char key1)
{
if (islower(key1))
key1 -= 'a';
if (isupper(key1))
key1 -= 'A';
return key1;
}
Тест для ровно двух аргументов и непустого ключа перемещен в верхнюю часть. Это немного отличается от того, что было предложено в комментариях. Сообщения об ошибках печатаются со стандартной ошибкой, а не со стандартным выводом. Вероятно, я бы заменил второе сообщение об использовании более конкретной ошибкой - the key may only contain alphabetic characters
или около того. И ошибки должны включать argv[0]
в качестве имени программы, а не в жестком кодировании имени. Цикл проверки ключа проверяет, что ключ является буквенным, вместо того, чтобы проверять, не являются ли они цифрами - имеется больше классов символов, чем цифр и букв. Код использует keyidx
и keylen
для отслеживания длины ключа и положения в нем. Я использую однобуквенные имена переменных, но обычно только для индексов цикла или простых указателей (обычно указателей на строки);в противном случае я использую короткие полумнемические имена. Существует два вызова shift()
, поэтому keyidx
увеличивается только тогда, когда вводимый символ является буквой. Есть и другие способы, которыми это может быть закодировано.
Одним очень важным изменением, не предсказанным в комментариях, является изменение типа для t
- с char
на int
. Когда это char
, если вы шифруете букву z
с буквой в конце алфавита (например, y
), значение 'z' + 24
выходит за пределы (подписанного) типа char
, преобладающего на машинах Intel, даваяотрицательное значение (чаще всего; формально поведение не определено). Это приводит к фиктивным результатам. Изменение на int
устраняет эту проблему. Поскольку значение t
в любом случае увеличивается до int
при передаче в printf()
, печать не наносит вреда. Я использовал подсказку plain text:
с пробелом, чтобы вход и выход совпадали на странице.
Я решил не использовать дополнительную локальную переменную k1
в shift()
. Я также использовал вычитание вместо модуля, как отмечено в комментариях.
Учитывая программу cc59
, созданную из cc59.c
, пример запуска:
$ cc59 bad
plain text: Dr. Oz
ciphertext: Er. Ra
$ cc59 zax
plain text: Er. Ra
ciphertext: Dr. Oz
$ cc59 ablewasiereisawelba
plain text: The quick brown fox jumps over the lazy dog. Pack my box with five dozen liquor jugs. The five boxing wizards jump quickly. How vexingly quick daft zebras jump. Bright vixens jump; dozy fowl quack.
ciphertext: Tip uqius fisef fkb uvmpt zzar lpi cehq dkk. Abck nj fkx oqxy jqne zskfn ljbykr bckj. Xpw fezp coxjyk sirivuw rmml ufjckmj. Lkw nmbzrody mytdk dbqx vetzej ncep. Xvthht wtbank rydt; lgzu jzxl qvlgg.
$ cc59 azpweaiswjwsiaewpza
plain text: Tip uqius fisef fkb uvmpt zzar lpi cehq dkk. Abck nj fkx oqxy jqne zskfn ljbykr bckj. Xpw fezp coxjyk sirivuw rmml ufjckmj. Lkw nmbzrody mytdk dbqx vetzej ncep. Xvthht wtbank rydt; lgzu jzxl qvlgg.
ciphertext: The quick brown fox jumps over the lazy dog. Pack my box with five dozen liquor jugs. The five boxing wizards jump quickly. How vexingly quick daft zebras jump. Bright vixens jump; dozy fowl quack.
$
Ключи дешифрования были полученысопоставляя буквы «шифрования» в строке 1 с буквами дешифрования в строке 2 данных:
abcdefghijklmnopqrstuvwxyz
azyxwvutsrqponmlkjihgfedcb
При шифровании и дешифровании наиболее простой кислотный тест для кода заключается в том, что программа может расшифровать еесобственный зашифрованный вывод с правильным ключом дешифрования и зашифрованным текстом.