凯撒密码与扭曲(神秘错误)

Caesar Cipher with a twist (Mysterious Error)

本文关键字:错误 密码 凯撒      更新时间:2023-10-16

我被分配编写一个密码,该密码接收一个带有字符的文件,并将所有字符更改为一个数字(1-10(。困难的部分是加密中需要的内容。"每次处理新行时,键值都会递增 1。但是,键每五行(旋转值(重置一次并返回到其原始值">

例如:如果用户输入 3 作为密钥,则第 1、2、3、4 和 5 行分别使用 3、4、5、6 和 7 进行加密。然后用 3 加密第 6 行,依此类推。

目前,我什至无法获得简单的班次来正常工作。没有任何语法错误,它的编译没有错误。但是,当我打开输出文件时,我的文本编辑器崩溃了,因为我以某种方式创建了一个 510mb 的文本文件.....我知道:/

因此,我正在寻找您愿意提供的任何帮助。已经为此工作了几个小时,并认为是时候寻求一些帮助了。提前感谢大家提供任何建议/解决方案,您愿意花时间提供。:)

/*
*File: Lab5
*Author: Nathaniel Goodhue
*Created on: 10/14/15
*Description: Encrypts an input message by
*shifting characters by a given number        
*/
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <fstream>
using namespace std;
/*
*Displays a menu that allows the user to set a shift key value,
*encrypt or decrypt a message, or quit
*/
void displayMenu()
{
   cout<<"1. Set the shift key value"<<endl;
   cout<<"2. Encrypt"<<endl;
   cout<<"3. Decrypt"<<endl;
   cout<<"4. Quit"<<endl;
}
/*
*gets the value that characters will be shifted by
*/
int getKeyValue(int &keyValue)
{
   keyValue = 0;
   do
   {
      cout<<"Enter the shift key value between 1 and 10: ";
      cin >>keyValue;
      if(keyValue >10 ||keyValue <1)
         cout<<"Key value must be between 1 and 10."<<endl;
   }
   while(keyValue >10 || keyValue <1);
   return keyValue;
}
/*
*gets the input and output file names
*/
void getFileNames(ifstream &fin1, ofstream &fout1, ifstream  &fin2, ofstream &fout2)
{
   fin1.open("inputMsg.txt");
   fout1.open("encryptedMsg.txt");
   fin2.open("encriptedMsg.txt");
   fout2.open("revertedMsg.txt");
}
/*
*shifts characters in input file by (int keyValue)
*/
void encrypt(int &keyValue, ifstream &fin1, ofstream &fout1)
{
   char ch;
   while(!fin1.eof())
   { 
      fin1.get(ch);
      while(ch != ' ')
      {
         fout1<<static_cast <char> (static_cast <int>(ch)+keyValue);
      }
   }
}
/*
*shifts characters back to original 
*/
void decrypt(int &keyValue, ifstream &fin2, ofstream &fout2)
{
   char ch;
   while(!fin2.eof())
   {
      fin2.get(ch);
      while(ch != ' ')
      {
         fout2<<static_cast <char> (static_cast <int>(ch)-keyValue);
      }
   }
}
int main()
{
   int menuChoice, keyValue;
   ifstream fin1;
   ofstream fout1;
   ifstream fin2;
   ofstream fout2;
   getFileNames(fin1, fout1, fin2, fout2);
   do{   
      displayMenu();
      cin >> menuChoice;
      if (menuChoice == 1)
      {
         getKeyValue(keyValue);
      }  
      else if (menuChoice == 2)
      {
     cout<<"Message successfully encrypted with "<<keyValue<<" as its key value"<<endl;
         encrypt(keyValue, fin1, fout1);
      }
      else if (menuChoice == 3)
      {
         cout<<"Message successfully decrypted with "<<keyValue<<" as its key value"<<endl;
         decrypt(keyValue, fin2, fout2);
      }
      else if(menuChoice > 4 || menuChoice < 1)
         cout<<"Invalid menu choice. Must be between 1 and 4";
   }
   while(menuChoice != 4);
   fin1.close();
   fout1.close();
   fin2.close();
   fout2.close();
   return 0;
}

我有 4 个文件的原因也是因为需要解密功能。

您的问题出在加密功能上。具体来说,这位:

  fin1.get(ch);
  while(ch != ' ')
  {
     fout1<<static_cast <char> (static_cast <int>(ch)+keyValue);
  }

在第一次运行循环时,fin1.get(ch) ch设置为输入文件的第一个字符。然后你进入一个while循环,将(密码(第一个字符一遍又一遍地放入文件中,直到ch是一个空格。但是您在此循环之外读取下一个字符,因此永远不会达到结束循环的条件。

只需要一个简单的if语句即可避免密码空格。除此之外,您当前的代码将始终拾取(和密码(EOF,因为EOF位直到您尝试读取文件的末尾才会被设置(这是在循环中完成的,因此直到您密码并附加到文件之后才被检查(。您可以使用 ifstream 的good()来检查循环中是否存在任何问题(EOF 或错误(,如果是,则break,以避免 EOF 在末尾导致额外的字符:

void encrypt(int &keyValue, ifstream &fin1, ofstream &fout1)
{
   char ch;
   while(fin1.get(ch))
   {
      if(!fin1.good()) break;
      if (ch != ' ') fout1<<static_cast <char> (static_cast <int>(ch)+keyValue);
      else fout1<<' ';
   }
}

您还需要对解密进行类似的更改。另外,为了挑剔,我建议

cout<<"Message successfully encrypted with "<<keyValue<<" as its key value"<<endl;

并且相应的解密行应该在加密/解密成功之后出现,而不是之前。

另一个问题是文件流在程序开始时打开并在结束时关闭的方式。如果您尝试在程序的同一运行中加密和解密消息,这将失败,因为fin2在消息实际写入之前打开encryptedMsg.txtfout1(将加密消息写入该文件(需要首先关闭。

实际上,我建议一般情况下,您只在需要时打开流。与其在开头打开所有流并在结束时关闭所有流,不如在加密消息之前打开fin1(输入消息(和fout1(加密输出(,然后立即关闭它们。同样,在解密之前立即打开fin2(加密消息作为输入(和fout2(解密版本(,然后立即关闭它们。或者,更好的是,您可以重用流 - 只需有一个ifstream对象和一个ofstream对象,每个对象在加密/解密前后打开和关闭相应的文件。

您的程序永远不会停止读取输入文件。如果您的输入文件不包含空格字符,则此循环将永远运行,这就是导致输出非常大的原因。

while(ch != ' ')

将这两行更改为

while(fin1.good())

使其在文件末尾 (EOF( 停止。

不要尝试一次完成所有操作。 从一个简单的程序开始读取文件并对其执行标准的凯撒班次。 当且仅当您正常工作时,才使用步进键进入第二阶段。

这样做可以一次处理几个错误,而不是将它们全部混为一谈。 找出代码的哪个部分导致错误也更容易。