我正在写一个密码程序。程序首先要求用户输入包含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重复两次
答案 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;
}
你的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;
}