2017-01-21 5 views
1

Прежде всего не существует один, что я могу задать такой вопрос так не простите пожалуйста мнеVigenere Cipher - Формула Объяснение

#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; 
} 

Я совсем не могу получить эти 2 строки кода

key[i] = key[i] - 97; 
printf("%c", (((txt[k] - 97) + (key[k % l])) % 26 + 97)); 

Есть ли легкое объяснение, почему мы использовали первый и как работает второй?

+1

Вы можете проверить [ASCII код 97] (http://www.theasciicode.com.ar/ascii-printable-characters/lowercase- letter-a-minuscule-ascii-code-97.html), который кажется «a». И 26 может иметь какое-то отношение к числу символов в алфавите. –

ответ

1

Ключа, используемый для шифра Виженера, как предполагается, все буквы. Первое выражение преобразует строку в массив смещений, 0 для a, 1 для b и т. Д. 97 - код ASCII для 'a'. Было бы более удобным для чтения, чтобы записать:

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 является ASCII код 'a',
  • это добавляет значение сдвига key[k % l], езда на велосипеде значения в key по кругу,
  • для получения индекса букв между 0 и 25.
  • он, наконец, добавляет 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; 
} 
+0

«unsigned char» это важно добавить или? – kryin10

+0

@ kryin10: 'islower()' и друзья определяются только для значений типа 'unsigned char' и специального значения' EOF'. Если тип 'char' по умолчанию подписан в вашей системе, что наиболее вероятно, и если вы наберете некоторые расширенные символы, такие как' é', они имеют отрицательное значение, для которого 'islower()' имеет неопределенное поведение. Выдача аргументов 'char' как' (unsigned char) 'является стандартным способом избежать этой проблемы. – chqrlie

+0

спасибо за помощь. Я думаю, что программа не пропускает пространство. Я попытался добавить, если это не пробел и строка '', но он, похоже, не работает. любые советы для этого? – kryin10

0
key[i] = key[i] - 97; 

использование этой линии в том, чтобы дать ключ [I], значение которого представляет собой значение carácter в ASCII это индекс в нашем алфавите. Затем, 'а' будет дано значение 0, 'B' значение 1 ...., и 'Z' значение 25.

Что касается второй линии,

printf("%c", (((txt[k] - 97) + (key[k % l])) % 26 + 97)) 

он печатает значение carii, которое имеет значение ascii, равно

(((txt[k] - 97) + (key[k % l])) % 26 + 97)) 

Выравнивание 97 имеет ту же цель, что и описано выше.

Модуль% 26 является модулем, то есть остатком ((txt [k] - 97) + (клавиша [k% l])) при делении на 26 (целочисленное деление). Затем добавляется 97, чтобы преобразовать порядок или индекс результата в соответствующее значение ascii. Эта страница может дать вам более подробную информацию о представлении символов в C.

Что касается значения k, i и l, я позволяю вам самостоятельно понять внутреннюю функцию cypher, но все шифрование происходит в вторая строка, о которой вы хотели объяснить.

PS: Части с «65» таким же, но с заглавными буквами, так как «A» значение в ASCII составляет 65