Гораздо проще показать, чем объяснить:
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
if (argc != 2)
{
fprintf(stderr, "Usage: %s keyword\n", argv[0]);
return 1;
}
for (int i = 1; i < argc; i++)
{
for (int j = 0; argv[i][j] != '\0'; j++)
{
if (isalpha(argv[i][j]) == false)
{
fprintf(stderr, "%s: non-alphabetic character '%c' (%d) in key\n",
argv[0], argv[i][j], argv[i][j]);
return 1;
}
}
}
string pt = get_string("plaintext: ");
printf("ciphertext: ");
int k = 0;
int keylen = strlen(argv[1]);
for (int r = 0; pt[r] != '\0'; r++)
{
if (isupper(pt[r]))
{
int j = k++ % keylen;
int key = tolower(argv[1][j]) - 'a';
printf("%c", (pt[r] - 'A' + key) % 26 + 'A');
}
else if (islower(pt[r]))
{
int j = k++ % keylen;
int key = tolower(argv[1][j]) - 'a';
printf("%c", (pt[r] - 'a' + key) % 26 + 'a');
}
else
{
printf("%c", pt[r]);
}
}
printf("\n");
return 0;
}
Пример выполнения:
$ ./vig89 baz
plaintext: Hello, World!
ciphertext: Iekmo, Vprke!
$
Как я отметил в комментарии, вам нужно отделить 'позицию в строке, r
'из' зашифрованного номера символа '.Вам нужна дополнительная переменная, которую вы увеличиваете, только когда символ алфавитный.
В приведенном выше коде k
- дополнительная переменная (keylen
- другая, но она просто записывает длину ключа, а нечем неоднократно звонить strlen()
).Значение в k
увеличивается, когда известно, что символ является буквой, а не иначе.
Я заметил, что может быть целесообразно обработать argv[1]
, чтобы вам не приходилось выполнятьtolower()
конвертация каждый раз;Вы можете сделать это при проверке ключевого слова.
Я также сообщал об ошибках при стандартной ошибке и не использовал strlen()
в условной части циклов.Хотя стоимость не слишком высока, если вы имеете дело с трехбуквенными ключами, если вы начнете вычислять длину строки длиной 20 КиБ на каждой итерации, вы можете начать обнаруживать накладные расходы (если компилятору не удастся их оптимизировать)- может, а может и нет).Я также выровнял простой текст и зашифрованный текст в I / O.
Есть много других изменений, которые можно / нужно сделать.Например, первый цикл for (int i = 1; …)
не нужен;у вас есть только один аргумент, поэтому вам нужен только внутренний цикл for (int j = 0; …)
.Также более логично использовать if (!isalpha(argv[i][j]))
, чем сравнивать результат с false
, тем более что макрос isalpha
не гарантирует возврата 0 или 1 (он возвращает ноль или не ноль)- поэтому изменение if (isalpha(argv[i][j]) == false)
на if (isalpha(argv[i][j] != true)
не будет надежным.Вероятно, я бы создал простую переменную char *key = argv[1];
(или string key = argv[1];
в контексте CS50, хотя я не уверен, что CS50 typedef char *string;
- хорошая идея) и использовал бы ее в программе.