[英]Undefined behaviour with function returning pointer
EDIT: The problem was not undefined behaviour, but rather "mis-use" of char-arrays 编辑:问题不是未定义的行为,而是字符数组的“滥用”
I haven't worked a lot with pointers and dynamic memory allocation, so I decided I'd try to make a really simple encrypter using these methods. 我在指针和动态内存分配方面工作不多,所以我决定尝试使用这些方法制作一个非常简单的加密器。 (this encrypter isn't supposed to be great, it uses Caesars method, only +1 instead of 3, and uses symbols in between the letters to make it harder to decrypt, not here for criticism on the algorithm) (这种加密程序本来就不理想,它使用Caesars方法,仅+1而不是3,并且在字母之间使用符号使解密变得更加困难,此处不批评算法)
The problem I'm facing I believe is undefined behaviour, but I don't really see how this happens. 我认为我所面临的问题是不确定的行为,但我并没有真正看到这种情况如何发生。 Say I want "Hello" to be encrypted, it only prints 'I', which comes after 'H' in the alphabet, but it stops there and the program becomes unresponsive, so I suppose the problem lies in the else
part of the for loop. 假设我希望对“ Hello”进行加密,它仅打印“ I”,该字母在字母“ H”之后,但是在此停止并且程序变得无响应,因此我想问题出在for的else
部分环。 The compiler also warns me about heap corruption, but after looking through this page I think I'm freeing the memory correctly. 编译器还警告我有关堆损坏的信息,但是浏览完此页面后,我认为我正在正确释放内存。
#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;
}
As a sidenote, I do realize that vectors might be better for this purpose, but I haven't gotten into that just yet, this is for practicing memory management. 附带一提,我确实意识到矢量可能会更好地达到此目的,但是我还没有深入到这,这是为了练习内存管理。
cout << *bar;
is printing the first character that bar points to. 正在打印栏指向的第一个字符。
You want 你要
cout << bar;
But for that you would need to null terminate the returned string. 但是为此,您需要将终止返回的字符串为null。
Side notes: please don't use raw pointers. 旁注:请不要使用原始指针。 disg
should be for example a std::array
. 例如, disg
应该是std::array
。 And enc
should return a std::string
. 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
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
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
encrypted[i + 1] = disg[rand() % 37] ;
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] ;
. 。 But you will better see that if you remove the wrong if. 但是您会更好地看到,如果删除错误的if。
And for (int i = 0; i < str.size(); i++)
could be rewritten as for(auto c : str)
. 并且for (int i = 0; i < str.size(); i++)
可以重写为for(auto c : str)
。
Lets take a closer look at the loop in the enc
function: 让我们仔细看看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];
}
The loop will iterate with i
from 0
to str.size() - 1
(inclusive). 循环将使用i
从0
迭代到str.size() - 1
(含str.size() - 1
)。 That means the condition inside the loop, i == str.size()
will never be true, and you will for the last iteration write out of bounds in the else
clause. 这意味着循环内的条件i == str.size()
永远不会为真,并且对于最后一次迭代,您将在else
子句中写出边界 。
The solution is to change the condition in the if
to i == str.size() - 1
. 解决方案是将if
的条件更改为i == str.size() - 1
。
There are some other problems as well, but none that will lead to UB like the above. 还有其他一些问题,但没有一个会像上面那样导致UB。 For example, the value you write to encrypted[i + 1]
will be overwritten the very next iteration. 例如,您写入encrypted[i + 1]
将在下一个迭代中被覆盖。
but I don't know how I can initialize a string with dynamic size 但我不知道如何初始化具有动态大小的字符串
I've taken your code and modified it, to use a std::string
and removed the allocations as they are simply not needed here. 我已将您的代码修改为使用std::string
并删除了分配,因为这里根本不需要它们。
Please read up on the code, debug it, and check the comments. 请阅读代码,对其进行调试,然后检查注释。
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;
}
As a sidenote, I do realize that vectors might be better for this purpose, but I haven't gotten into that just yet, this is for practicing memory management. 附带一提,我确实意识到矢量可能会更好地达到此目的,但是我还没有深入到这,这是为了练习内存管理。
You could use a std::vector
but it is here also not neccessary. 您可以使用std::vector
但这在这里也不是必需的。 You will rarely have to deal with raw pointers in modern C++. 您几乎不需要在现代C ++中处理原始指针。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.