我的字符串末尾有4个相同的垃圾字符

时间:2019-07-14 23:53:18

标签: c++

因此,每当我运行程序时,它都会根据需要打印出字符串,但是每次都在末尾添加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);
}

我希望输出只是没有尾随“²²²”的字符串

2 个答案:

答案 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'的缺失会导致您的帖子最初出现问题。除非您在某处的紧密循环中使用此函数,否则不太可能在性能上取得巨大的成功,但是一点点的帮助都可以,无论如何,您都应该养成编写此优化的习惯,因为这样做通常也是好的编程习惯这样。