О CS50 pset2 Vigenere - PullRequest
       67

О CS50 pset2 Vigenere

0 голосов
/ 26 декабря 2018

Почему мой код не пропустил пробел, и это привело к неправильной последовательности шифрования?

Когда я проверяю пример «Hello, World!», Мой код также подсчитал пробел и преобразовал в «Iekmo,Wnslc!»вместо "Иэкмо, Впрке!"используя ключ "баз"

Может кто-нибудь объяснить логику позади?Большое спасибо!

#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>

//getting user encryption key


int main(int argc, string argv[])
{

    if (argc != 2)
    {
        printf("Usage: ./vigenere keyword\n");
        return 1;
    }
    //check if all are alphabeticals
    else 
    {
           for (int i = 1; i < argc; i++)
        {
            for (int j = 0; j < strlen(argv[i]); j++)
            {
                if (isalpha(argv[i][j]) == false)
                {                
                    printf("Usage: ./vigenere keyword\n");
                    return 1;
                }
            }
        }
    }  


    //getting plaintext divide it into each character
    string pt = get_string("plaintext: ");

    printf("ciphertext: ");
    //convert to ciphertext
    //C = (P + k) % 26
    for (int r = 0; r < strlen(pt); r++)
    {                           
        if (isupper(pt[r]))
        {
            //making loop with j group corresponding to keyword
            int j = r % strlen(argv[1]);
            int key = tolower(argv[1][j]) - 97;
            printf("%c", (pt[r] - 65 + key) % 26 + 65);
        }
        else if (islower(pt[r]))
        {
            //making loop with j group corresponding to keyword
            int j = r % strlen(argv[1]);
            int key = tolower(argv[1][j]) - 97;
            printf("%c", (pt[r] - 97 + key) % 26 + 97);
        }
        else
        {
            printf("%c", pt[r]);
        }

     }            
       printf("\n");       

}

Ответы [ 2 ]

0 голосов
/ 26 декабря 2018

Гораздо проще показать, чем объяснить:

#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; - хорошая идея) и использовал бы ее в программе.

0 голосов
/ 26 декабря 2018

Проблема с вычислением j здесь int j = r % strlen(argv[1]);.Индекс ключа не связан с r (индекс сообщения).Программа должна перебирать ключ, основываясь исключительно на (длине) ключа.Вам нужно увеличивать его каждый раз, когда вы «используете» ключевой индекс и «оборачиваете» его, чтобы он не проходил до конца.Вы могли бы рассмотреть объявление j перед циклом r;увеличивать j всякий раз, когда вы используете индекс ключа (подсказка: j++);и "обернуть" j с помощью оператора по модулю (подсказка: j % strlen(argv[1]).Я оставляю фактический код для вас.

...