编辑:问题不是未定义的行为,而是“错误使用”char数组
我没有使用指针和动态内存分配,因此我决定尝试使用这些方法制作一个非常简单的加密器。 (这个加密器不应该很好,它使用Caesars方法,只有+1而不是3,并且在字母之间使用符号使其更难解密,而不是在这里批评算法)
我所面临的问题我认为是未定义的行为,但我真的不知道这是怎么发生的。假设我希望“Hello”加密,它只打印'I',它出现在字母表中的'H'之后,但它停在那里并且程序没有响应,所以我认为问题在于else
for循环的一部分。编译器还警告我有关堆损坏的信息,但在查看此页面后,我认为我正在释放内存。
#include <iostream>
#include <string>
#include <ctime>
using namespace std;
char * enc(string);
int main()
{
string foo = "Hello";
char * bar = enc(foo);
cout << *bar;
delete[] bar;
cin.get();
return 0;
}
char * enc(string str)
{
char * encrypted = new char[int(str.size())];
srand(unsigned int(time(NULL)));
// Disguise symbols for obscurifying text
char * disg = new char[37]
{
//37 symbols, unrelevant and takes a lot of space.
};
for (int i = 0; i < str.size(); i++)
{
encrypted[i] = int(str[i]) + 1;
if (i == str.size())
break;
else
encrypted[i + 1] = disg[rand() % 37];
}
delete[] disg;
return encrypted;
}
作为旁注,我确实意识到向量可能更好用于此目的,但我还没有进入那个,这是为了练习内存管理。
答案 0 :(得分:1)
cout << *bar;
正在打印条指向的第一个字符。
你想要
cout << bar;
但是为此你需要null来终止返回的字符串。
附注:请不要使用原始指针。 disg
应为std::array
。 enc
应返回std::string
。
if (i == str.size()
)can never be true inside your loop. Also as Some programmer dude says in his answer you are writing out of bounds in the line
已加密[i + 1] = disg [rand()%37] ;
。但是如果你删除错误的话,你会更好地看到。
for (int i = 0; i < str.size(); i++)
可以改写为for(auto c : str)
。
答案 1 :(得分:1)
让我们仔细看看enc
函数中的循环:
for (int i = 0; i < str.size(); i++)
{
encrypted[i] = int(str[i]) + 1;
if (i == str.size())
break;
else
encrypted[i + 1] = disg[rand() % 37];
}
循环将使用i
从0
到str.size() - 1
(包括)进行迭代。这意味着循环中的条件,i == str.size()
永远不会为真,并且您将在最后一次迭代中在else
中写出越界子句。
解决方案是将if
中的条件更改为i == str.size() - 1
。
还有一些其他问题,但没有一个会像上面那样导致UB。例如,您写入encrypted[i + 1]
的值将在下一次迭代时被覆盖。
答案 2 :(得分:1)
但我不知道如何初始化动态大小的字符串
我已经使用了您的代码并对其进行了修改,以使用std::string
并删除了分配,因为这里根本不需要它们。
请阅读代码,调试代码并查看评论。
class Enc
{
public:
//For arrays of fixed size, you may use this to obtain the size of the given array
template <typename T, std::size_t N>
constexpr static std::size_t FixedArraySize(T(&arr)[N])
{
return N;
}
//The parameter should not be modified, pass it as constant value by reference
static std::string enc(const std::string &str)
{
//It looks like your symbols do not change, let's make them static to initialize only once
static char symbols[] =
{
'A', 'x', '!' //...
};
auto originalStringSize = str.size();
//Create the destination string and resize it to the source string's length
std::string encrypted;
encrypted.resize(originalStringSize);
//Your loop
for (int i = 0; i < originalStringSize; ++i)
{
//Make safe cast, which is also obvious to the reader of the code
encrypted[i] = static_cast<int>(str[i]) + 1;
//Fixed with - 1 to break correctly
if (i == (originalStringSize - 1))
break;
else
encrypted[i + 1] = symbols[rand() % FixedArraySize(symbols)]; //Notice the helper function
}
//Return the 'encrypted' string
return encrypted;
}
};
int wmain(int, wchar_t**)
{
std::string testString = "Hello World";
//Call srand only once in your program !
srand(static_cast<unsigned int>(time(nullptr)));
auto encrypted = Enc::enc(testString);
std::cout << encrypted << std::endl;
return 0;
}
作为旁注,我确实意识到向量可能更好用于此目的,但我还没有进入那个,这是为了练习内存管理。
您可以使用std::vector
但这里也不是必需的。您很少需要处理现代C ++中的原始指针。