密码不会正确加密(携带太多字符)

时间:2014-01-28 04:08:42

标签: c++ string encryption c-strings

我正在写一个密码程序。程序首先要求用户输入包含8个或更多字符的密码,包括字符和标点符号。

之后,程序将“加密”密码,方法是将密码的后半部分移到前面,在中间添加一个“+”,然后将前半部分追加到最后。

我遇到的问题是,每当我输入一个奇数字符的密码时,它会复制最后一个字符两次,并且会破坏我的程序。我该如何解决?我知道我必须添加一个条件,因为有奇怪的字符,但idk它应该包括什么。这是我的代码:

// write a function to encrypt the password:
// return a dynamically allocated C string of the exact size (no extra room) with:
// the last half of the password, the + symbol, and then the first half of the password
char * encrypt (char pw[])
 {
int exactsize = strlen(pw) + 2;
char * encPW = new char[exactsize];
int mid = exactsize / 2;


strcpy(encPW, pw + mid);
strcat(encPW, "+");
strncat(encPW, pw, exactsize - mid);

return encPW;

 }

 // write the same (overloaded) function for a C++ String
 char * encrypt (string pw)
 {
int exactsize = pw.length() + 2;
char * encPW = new char[exactsize];
int mid = exactsize / 2;

string temp(pw, mid);
string temp2(pw, 0 ,mid);
temp = temp + "+" + temp2;

strcpy(encPW, temp.c_str());


return encPW;
}

here is the output i am getting and what i am talking about:
Enter your password: salehrocks93
add punctuation
Enter your password: salehrocks93/
Valid password format. Encrypting...

Encrypted password: cks93/+salehroc

Enter your new password: salehrocks93/
New Encrypted password: cks93/+salehro
1
Press any key to continue . . .

当它第一次要求输入密码并加密时,c重复两次

2 个答案:

答案 0 :(得分:1)

我喜欢这样的问题怎么办? 逐步完成它们。我发现通常会有所帮助。好的'笔和纸调试。如果你无法在纸上弄明白,你将如何在电脑中弄明白?! 电线太多了!

因此。让我们一步一步。首先,我们需要选择一个假参数来传递它。


为了演示的目的,让我们使用C风格,以NULL结尾的字符串“PASSWOR”。如果我要绘制这个数组,它可能看起来像这样:

['P'].['A'].['S'].['S'].['W'].['O'].['R']

好的,现在你的代码。

char * encrypt (char pw[])
 {
  int exactsize = strlen(pw) + 2;
  char * encPW = new char[exactsize];
  int mid = exactsize / 2;

这里我们处于你的功能的开始。您已使用字符串的长度和幻数声明了变量 exactsize 。我的猜测是你使用这个幻数来说明NULL终结符和你想要添加的'+'。

所以,我们的假参数“PASSWOR”,我们应该得到 7 的strlen(),使我们的'exactsize' 9

然后你分配一个字符数组 encPW ,作为这个新的'确切'大小。以下是encPW现在的样子,作为一个字符数组

// initial value
[ 0 ].[ 0 ].[ 0 ].[ 0 ].[ 0 ].[ 0 ].[ 0 ].[ 0 ].[ 0 ]
// with indices
  0     1     2     3     4     5     6     7     8

然后你声明 mid ,我认为我们可以安全地假设这意味着中点。这有点棘手但是因为你在参考你的新尺码时确定了中间位置。但是,让我们坚持手头的代码。由于 exactsize 9 ,因此mid应 4.5 。但它是一个整数,所以最终结果是 4 。我们继续。

strcpy(encPW, pw + mid);

现在你从pw + mid开始进入encPW的目的地。 pw + mid为我们提供了指向原始字符串中'W'字符的指针。它将复制到并包括NULL终止符。

// now what do we have?
['W'].['O'].['R'].[ 0 ].[ 0 ].[ 0 ].[ 0 ].[ 0 ].[ 0 ]

然后将'+'追加到字符串:

strcat(encPW, "+");
// now what do we have?
[ 'W' ].[ 'O' ].[ 'R' ].[ '+' ].[ 0 ].[ 0 ].[ 0 ].[ 0 ].[ 0 ]

最后,调用 strncat(),它将 num 字符附加到C风格的字符串 plus 一个NULL终止符。

您告诉它将exactsize - mid个字符写入字符串。由于 exactsize 为9, mid 为4,我们会告诉它写 5 字符。

  

如上所述,strncat还会写一个NULL终止符。这是6个字符!但是,正如我们所看到的那样(通过计算0中的左侧)   上面的字符串),在我们写作之前只剩下5个字符   进入不属于我们的记忆!

这是在幕后发生的事情(在高层次上)

strncat(encPW, pw, exactsize - mid)
// strncat tries to write this stuff at the end
[ 'W' ].[ 'O' ].[ 'R' ].[ '+' ].[ 'P' ].[ 'A' ].[ 'S' ].[ 'S' ].[ 'W' ].[ 0 ]
                                                                         .^
                                      Uh oh, somebody call the memory police!

然而,即使我们没有写入可怕的,神秘的记忆,算法仍然会出现根本性的缺陷,因为我们的一个角色出现了两次!


我的问题是: mid 是什么?当你宣布它时,你打算如何使用它?

现在,我们想出了简单的笔和纸修复。


我将如何解决这个问题:

int mid = strlen(pw) / 2;

对于你的strncat(),我会使用

strncat(encPW, pw, mid)

这为我们解决了一些问题。让我们使用两个例子,“PASSWOR”和“PASSWORD”。

  

使用“PASSWOR”,mid将是3

     

pw + mid将'S'(第二个s)

     

在strcpy encPW之后将是“SWOR”

     

在第一个strcat之后,它将是“SWOR +”

     

strncat(encPW, pw, mid)之后,它将是“SWOR + PAS”。

理想,是吗?

  

使用“PASSWORD”,mid将是4

     

pw + mid将'W'

     

strcpy encPW之后会是“WORD”

     

在第一个strcat之后,它将是“WORD +”

     

strncat(encPW, pw, mid)之后,它将是“WORD + PASS”。

答案 1 :(得分:0)

#include <iostream>
#include <string>

void encrypt(const std::string& password)
{
    size_t exactSize = password.length() + sizeof('+') + sizeof('\0');
    size_t mid = exactSize / 2;

    std::cout << "password = " << password
              << ", exactSize = " << exactSize
              << ", mid = " << mid
              << ", password[0,mid) = " << password.substr(0, mid)
              << ", password[mid,npos) = " << password.substr(mid, std::string::npos)
              << '\n';

    std::string t1(password, mid);
    std::string t2(password, 0, mid);

    std::cout << "t1 = " << t1 << ", t2 = " << t2 << '\n';
}

int main()
{
    encrypt("12345678");
    encrypt("123456789");

    return 0;
}

生成输出http://ideone.com/fork/Y9GsHM

password = 12345678,  exactSize = 10, mid = 5, password[0,mid) = 12345, password[mid,npos) = 678
t1 = 678, t2 = 12345
password = 123456789, exactSize = 11, mid = 5, password[0,mid) = 12345, password[mid,npos) = 6789
t1 = 6789, t2 = 12345

问题是exactSize结果大小,包括'+'和'\ 0',而不是源字符串的大小。

#include <iostream>
#include <string>

void encrypt(const std::string& password)
{
    size_t mid = password.length() / 2;
    size_t exactSize = password.length() + sizeof('+') + sizeof('\0');

    std::cout << "password = " << password
              << ", exactSize = " << exactSize
              << ", mid = " << mid
              << ", password[0,mid) = " << password.substr(0, mid)
              << ", password[mid,npos) = " << password.substr(mid, std::string::npos)
              << '\n';

    std::string t1(password, mid);
    std::string t2(password, 0, mid);

    std::cout << "t1 = " << t1 << ", t2 = " << t2 << '\n';
}

int main()
{
    encrypt("12345678");
    encrypt("123456789");

    return 0;
}

http://ideone.com/E5YFKm

你的C-string版本也非常狡猾,我制作了上述代码的匹配C字符串版本。

#include <iostream>
#include <cstring>

void encrypt(const char* password)
{
    size_t len = strlen(password);
    size_t allocSize = strlen(password) + sizeof('+') + sizeof('\0');
    size_t mid = len / 2;

    char left[16];
    char right[16];

    strncpy(left, password, len - mid);
    left[len - mid] = '\0';
    strcpy(right, password + mid);

    std::cout << "password = " << password
              << ", len = " << len
              << ", remainder = " << (len - mid)
              << ", mid = " << mid
              << ", left = " << left
              << ", right = " << right
              << '\n';
}

int main()
{
    std::cout << "begin\n";
    encrypt("12345678");
    encrypt("123456789");

    return 0;
}

http://ideone.com/O6Na9t