С Виженера Шифрование


Этот код протестирован и работает должным образом, я ищу некоторую обратную связь на следующие функции. Довольно прямо вперед, и простой, но если дополнительная информация требуется, спросите и я с радостью помогу. Замечания, предложения и т. д. приветствуются.

Следующие методы функциональной части программы, которая служит применение шифрования Виженера.

В removeDuplicates функция служит для удаления дубликатов из введенного пользователем ключевую фразу, например, если infinitestring был принят в inftesrg будут возвращены.

targetFound служит помощником для выявления дубликатов представить как removeDuplicates строит окончательный ключ. Я понимаю, что это совершенно не нужна, но прототипы были поставлены в описании проекта, и пока я менять возвращать-типы и параметры, передаваемые, я все-таки решила использовать все указанные функции.

initializeEncryptArray строит шифрования таблица подстановки, initializeDecryptArray строит расшифровка таблица подстановки, однако это зависит от initializeEncryptArray в качестве параметров описания. Идея проявляется в следующем:

key: feather

cipher:
A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z
⇵ ⇵ ⇵ ⇵ ⇵ ⇵ ⇵ ⇵ ⇵ ⇵ ⇵ ⇵ ⇵ ⇵ ⇵ ⇵ ⇵ ⇵ ⇵ ⇵ ⇵ ⇵ ⇵ ⇵ ⇵ 
F|E|A|T|H|R|Z|Y|X|W|V|U|S|Q|P|O|N|M|L|K|J|I|G|D|C|B

processInput обрабатывает входной файл, указанный пользователем, и записывает в выходной файл.

По существу, в main мне разбирать аргументы, приведенные в командной строке, для шифрования/дешифрования (e или d) параметры входной файл и выходной файл, следующим образом ./a.out e <key-word> <input-file-name> <output-file-name> или ./a.out d <key-word> <input-file-name> <output-file-name>. Для шифрования параметр ключ передается removeDuplicates для удаления повторяющихся символов. Ключ (меньше повторяющихся символов), затем передается initializeEncryptArray а остальной алфавит прилагается в обратном порядке, чтобы создать таблица подстановки. Замена таблица передается processInput наряду со ссылками на входных и выходных файлов.

Такой же последовательности происходит для расшифровки варианта, за исключением после initializeEncryptArray результат передается initializeDecryptArray вместо processInput и результирующая таблица из initializeDecryptArray затем передается processInput наряду со ссылками на входных/выходных файлов.

П1.с:

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include "functions.h"


int main(int argc, char * argv[]){
  int MAXNUM = 27;
  char * encrypt, * decrypt, * key;
  char choice;
  FILE * fin, * fout;

  //check argument count
  if (argc != 5)
    errorHandler(0);

  choice = toupper(*argv[1]);
  key = removeDuplicates(argv[2]);

  fin = fopen(argv[3], "r");
  fout = fopen(argv[4],"w");

  if(fin == NULL || fout == NULL)
    errorHandler(3);

  encrypt = (char   *) malloc (MAXNUM * sizeof(char));

  //allocation check
  if (encrypt == NULL)
    errorHandler(2);

  //encrypt option
  if (choice == 'E'){
    initializeEncryptArray(key, encrypt);
    processInput(encrypt, fin, fout);
  }
  //decrypt option
  else if (choice == 'D'){
    decrypt = (char *)  malloc (MAXNUM * sizeof(char));

    if(decrypt == NULL)
      errorHandler(2);
    initializeEncryptArray(key, encrypt);
    initializeDecryptArray(encrypt, decrypt);
    processInput(decrypt, fin, fout);
    free(decrypt);
  }
  //invalid choice
  else
    errorHandler(1);

  free(encrypt);
  fclose(fin);
  fclose(fout);
}

функции.с:

 #include "functions.h"

// remove duplicate characters in array word and return the resulting string
char * removeDuplicates(char * word){
  char * result;
  int len = strlen(word) + 1;
  result = malloc (len);

  if (result == NULL){
    errorHandler(2);
  }

  char ch;

  for(int i = 0, j = 0; i < len; i++){
    ch = word[i];

    if(!targetFound(result, ch)){
      result[j] = ch;
      j++;
    }
    result[j] = '\0';
  }

  return result;
}

// search the first num characters in array charArray for character target
// return a non-zero integer if found, otherwise, return 0
int targetFound(char * charArray, char target){
  int found = 0;

  if(strchr(charArray,target))
    found = 1;

  return found;
}

// initialize the encrypt array with appropriate cipher letters according to the given key
void initializeEncryptArray(char * key, char * encrypt){
  char ch;

  for (int i = 0, j = 0, flag = 0; j < 27;){
    ch = key[i];

    if (ch == '\0' || flag == 1){
      if(flag == 0)
        flag = 1;

      ch = 'Z' - j;
      j++;
    }

    if (strchr(encrypt,ch) == NULL){
      encrypt[i] = toupper(ch);
      i++;
    }
  }
  encrypt[26] = '\0';
  printf("Encrypt: %s\n\n", encrypt);
}

// initialize the decrypt array with appropriate cipher letters according to the given key
void initializeDecryptArray(char * encrypt, char * decrypt){
  int i;
  for ( i = 0; i < 27; i++){
    decrypt[encrypt[i] - 'A'] = i + 65;
  }
  decrypt[26] = '\0';
  printf("Decrypt: %s\n\n", decrypt);
}

// process data from the input file and write the result to the output file
// pass the encrypt array to parameter substitute if encryption is intended
// pass the decrypt array to parameter substitute if decryption is intended
void processInput(char * substitute, FILE * fin, FILE * fout){
  char ch;
  while ( fscanf(fin, "%c", &ch) != EOF ){
    if(isupper(ch)){
      fprintf(fout, "%c", substitute[ch - 'A']);
    }
    else if(islower(ch)){
      fprintf(fout, "%c", tolower(substitute[ch - 'a']));
    }
    else
      fprintf(fout, "%c", ch);
    }
}

// prints errors based on the error code passed in
void errorHandler(int argIndex){
  switch(argIndex){
    case 0:
      printf("Error: Incorrect number of arguments received.\n\tPlease try again using the correct number of args.\n");
    case 1:
      printf("Error: Invalid program option.\n\tPlease try again using either 'd'/'D' or 'e'/'E'.\n");
    case 2:
      printf("Error: Memory could not be allocated.\n");
    case 3:
      printf("Error: Invalid input filename given for input.\n\tPlease use a valid filename for input.\n");
  }
  exit(1);
}

функции.ч

#ifndef FUNCTIONS_H
#define FUNCTIONS_H

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <string.h>

// remove duplicate characters in array word and return the resulting string
char * removeDuplicates(char * word);

// search the first num characters in array charArray for character target
// return a non-zero integer if found, otherwise, return 0
int targetFound(char * charArray, char target);

// initialize the encrypt array with appropriate cipher letters according to the given key
void initializeEncryptArray(char * key, char * encrypt);

// initialize decrypt array with appropriate substitute letters based on the encrypt array
void initializeDecryptArray(char * encrypt, char * decrypt);

// process data from the input file and write the result to the output file
// pass the encrypt array to parameter substitute if encryption is intended
// pass the decrypt array to parameter substitute if decryption is intended
void processInput(char * substitute, FILE * inf, FILE * outf);

//prints out user-friendly error message
void errorHandler(int errIndex);

#endif //FUNCTIONS_H


131
2
задан 19 февраля 2018 в 03:02 Источник Поделиться
Комментарии
1 ответ

Вот некоторые вещи, которые могут помочь вам улучшить вашу программу.

Исправить ошибки-часть 1

Первая проблема, мой компилятор заметил, что вы используете '/0' в нескольких местах, как будто это было равносильно '\0' что является NUL характер. Это не то же самое! То, что вы определяете, является многобайтовой символьной константы, которая, если он компилирует, конечно, не будет того, чего вы хотели.

Исправить ошибки часть 2

В removeDuplicates() функция выделяет память для result но память никогда не освобождается и он также используется до инициализации-их используют, как будто он имеет termminating NUL голец, но ни один не был вставлен код. Есть похожие ошибки в initializeEncryptArray рутина и несколько других мест, в которых неинициализированных данных используется. Хотя код вставляет NUL по окончании процедуры, он передает строку strchr() прежде чем это произойдет, что может привести к неопределенному поведению.

Обеспечить break для каждого case

Ваш обработчик ошибок содержит такой код:

switch(argIndex){
case 0:
printf("Error: Incorrect number of arguments received.\n\tPlease try again using the correct number of args.\n");
case 1:

Проблема в том, что вам не хватает break заявление в конце каждого дела. Это предполагает, что вы еще не протестировали программу очень много, что заставляет меня думать, что вы должны тратить больше времени на это, прежде чем представлять его на рассмотрение.

Думаю, пользователя

Допустив две ошибки выше, если пользователь запускает программу без аргументов, сообщение об ошибке такое:

Error: Incorrect number of arguments received.
Please try again using the correct number of args.

Это не очень полезно. Каково правильное количество аргументов и что они означают? Как правило, сообщение об ошибке должно сказать, что неправильно, а также, если возможно, дайте какую-то подсказку для пользователя о том, как это исправить.

Использовать const где практические

В MAXNUM переменная-это, видимо, размер шифрования массива и не меняется. По этой причине, я предлагаю, что он должен быть объявлен const int EncryptionArraySize = 27; вместо. Использование всех заглавных идентификатор, который традиционно был определен макрос, который это не.

Упростить код

Кодекс в настоящее время содержит эту строку:

encrypt = (char *) malloc (MAXNUM * sizeof(char));

Есть несколько вещей, которые я хотел бы изменить здесь, в дополнение к имени MAXNUM как уже упоминалось выше. Я бы написал это так:

encrypt = malloc(MAXNUM); 

Во-первых, malloc она обычно не требует броска. Во-вторых, sizeof(char) определяется по стандарту всегда быть равна одному, поэтому нет необходимости здесь.

Тщательно думать о выделении памяти

Потому что encrypt и decrypt массивы-это довольно короткий (27 символов), я бы, наверное, предположить, выделяя их как автоматические переменные (то есть стек переменных) исключает необходимость явного выделения/свободный и связанный с обработкой ошибок. Также removeDuplicates выделение памяти для result может быть легко устранена, выполнив удаления на месте:

char * removeDuplicates(char * word) {
for (char *ch = word; *ch; ) {
char *last = strrchr(ch, *ch);
if (last == ch) {
++ch;
continue;
}
for ( ; *last; ++last) {
*last = last[1];
}
}
return word;
}

Предпочитаю switch для if..else цепи

В main есть длинноватые if..else цепь, которая рассматривает пользователям выбор зашифровать или дешифровать и действует соответствующим образом. Что может быть более чистоплотными, описано как switch С default случае для обработки ошибки.

Переосмыслить интерфейс

Сейчас main код определяет длину ключа массива, используя именованную константу MAXNUMи это хорошо. Однако, эта длина потом взяла в initializeEncryptArray и initializeDecryptArray. Либо передать параметр или использовать тот факт, что это NUL завершенной строку (например, использование strlen()). Кроме того, я бы предложил removeDuplicates и initializeEncryptArray легко могут быть объединены.

2
ответ дан 19 февраля 2018 в 04:02 Источник Поделиться