因此,每当我运行程序时,它都会根据需要打印出字符串,但是每次都在末尾添加4个相同的“²”字符,而我不知道它们的来源。当我以发布模式而不是调试模式运行它时,它将在末尾打印一堆随机字符。 http://httpbin.org/post
#pragma once // this is all in a header file and building it in debug mode x86
#include "stdafx.h"
/* #ifdef __cplusplus
#define NULL 0
#else */
#define CurrentTime (__int16)0
std::string GenerateIdentifiers(const __int16 size)
{
srand(time(CurrentTime));
__int16 index{ 0 };
std::array<char, sizeof("ABCDEF0123456789")> UUID = {"ABCDEF0123456789"};
char *arrChar = new char[size];
for(__int16 x = 0; x < size; ++x)
{
index = rand() % ((sizeof(UUID) / sizeof(UUID[0]) - 1));
arrChar[x] = UUID[index];
}
return std::string(arrChar);
}
我希望输出只是没有尾随“²²²”的字符串
答案 0 :(得分:6)
arrChar
不是NUL终止的。 std::string
构造函数需要一个指向NUL终止的字符串的指针。您的程序通过缓冲区溢出表现出未定义的行为。
答案 1 :(得分:4)
这一定是我见过的最糟糕的代码。它包含一个主要的安全漏洞以及一些错误,包括内存泄漏。由于对使用::std::string
API的误解,在字符串末尾看到的有趣字符是您最少的担心。只是最可见的。
首先,在任何情况下都不应该为此目的使用rand
函数。如果您需要用于游戏或蒙特卡洛模拟的随机数生成器,则可以使用(但不是很好)的生成器。对于生成UUID,这是非常危险的。幸运的是,C ++标准委员会对此进行了思考,并创建了一种名为::std::random_device
的东西,它是获取安全随机数生成器的跨平台标准方法。
以下是使用适当的API的无错误版本的示例:
//#pragma once // this is all in a header file and building it in debug mode x86
//#include "stdafx.h"
#include <array>
#include <cstdint>
#include <random>
/* #ifdef __cplusplus
#define NULL nullptr
#else */
std::string GenerateIdentifiers(const ::std::uint16_t size)
{
using ::std::array;
static constexpr array<char, 16> hex_translate{'A', 'B', 'C', 'D', 'E', 'F', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
::std::random_device rd;
// Unfortunately uniform_int_distribution, unlike most other ranges, includes both ends.
// So a fixup to size() is needed because it's one past the end (like most ranges in C++).
::std::uniform_int_distribution<::std::uint16_t> dist(0, hex_translate.size() - 1);
::std::string uuid;
uuid.resize(size);
for(::std::uint16_t x = 0; x < size; ++x)
{
uuid[x] = hex_translate[dist(rd)];
}
return uuid;
}
已解决的问题...从字符串初始化::std::array
往往效果不佳。通常是因为字符串的末尾加上了额外的'\0'
(即sizeof("ABCDEF0123456789")
是17,而不是16)。可以使用一些不错的constexpr
库函数来解决此问题,但是如果没有此功能,最好的办法是使用字符列表代替,并明确说明其长度。
与尺寸问题有关,您对sizeof(UUID) / sizeof(UUID[0]) - 1
的使用很愚蠢。首先,将sizeof(char)
定义为1。其次,::std::array
具有可完美使用的size
成员函数,可用于此目的。最后,您对- 1
软糖因素的应用表明,您的程序有一个怪异的错误,您可以弄清楚您可以将- 1
放在某个地方而不是解决根本原因(尾随{{1 }}上保持不变。
此外,此数组的名称错误,这会使您的代码混乱。它不是UUID,而是一堆(乱序,但与此无关紧要)用于创建十六进制字符串的十六进制数字。因此,这是一个十六进制转换常量。而且它是恒定的。它永远不会在程序的整个生命周期内发生变化,因此应该为'\0'
和constexpr
。
此外,您使用static
分配字符数组new
,但从不释放它,从而导致内存泄漏。您不再应该在C ++中使用原始指针,这是为什么的教科书插图。您应该使用一种标准的C ++数据结构来保存动态大小的数据。并且恰好有一个arrChar
已经专门用于字符。
最后,您正在使用::std::string
生成随机数,该随机数可能会用于某种全局唯一标识符(通过使用UUID作为变量名来判断)。这是对该功能的完全不适当的使用。而且您播种的方式使情况变得更糟。您很有可能以这种方式生成冲突ID(两次运行该程序会生成相同的ID)。另外,这些ID可能会被外部第三方轻易猜测,并且经常使用此类ID的人希望它们在使用之前对任何人都是唯一且未知的。
从C ++ 11开始(代码的各种功能表明您可能正在使用),C ++能够生成安全且真正随机的数字作为标准库功能。合适的方法是将rand
与::std::random_device
结合使用。
作为奖励,对动态分配的字符数组使用::std::uniform_int_distribution
可使编译器应用返回值优化。它还消除了添加尾随::std::string
的需要,而尾随'\0'
的缺失会导致您的帖子最初出现问题。除非您在某处的紧密循环中使用此函数,否则不太可能在性能上取得巨大的成功,但是一点点的帮助都可以,无论如何,您都应该养成编写此优化的习惯,因为这样做通常也是好的编程习惯这样。