【问题标题】:Is std::array<char, size> null terminated?std::array<char, size> null 是否终止?
【发布时间】:2021-09-28 06:40:03
【问题描述】:

下面的sn-p代码安全吗?它调用了 std::string 的第四个构造函数,该构造函数接受一个指向空终止字符串的指针。问题是,我不确定下面的word 是否为空终止。是吗?

std::array<char, 4> word{'a', 'b', 'c', 'd'};

int main()
{
    std::string p = word.data();
    return 0;
}

【问题讨论】:

  • 没有。它不是以空值结尾的。要以 null 结尾,数组需要 5 个字符,最后一个是 0。您正在调用未定义的行为。
  • std::string 的第四个构造函数不接受指向空终止字符串的指针,它接受指向 char 的指针。开发人员必须注意空终止符。
  • @S.M.指向 char 的指针和指向空终止字符串的指针之间的区别在于指针的使用方式。语言本身没有区别。你是对的,确保空终止符是开发人员的责任。
  • std::string p(word.begin(), word.end());
  • @Evg 这是我以前的情况,但我处理的是std::array&lt;char, 50&gt;,当使用beginend 迭代器转换为字符串时,它有46 个空终止符。哈哈……

标签: c++ arrays string pointers char


【解决方案1】:

std::array 是否终止?

它可以包含一个以空字符结尾的字符串。它不一定包含以 null 结尾的字符串。

std::array<char, 4> word{'a', 'b', 'c', 'd'};

此数组不包含以空字符结尾的字符串。您可以判断,因为没有一个元素是空终止符。

std::string p = word.data();

此程序的行为未定义。

下面的sn-p代码安全吗?

没有。


如何使单词为空终止。

这是一个例子:

std::array<char, 5> word{'a', 'b', 'c', 'd'};

或者如果你想更明确:

std::array<char, 5> word{'a', 'b', 'c', 'd', '\0'};

【讨论】:

  • 如果您包含一个如何使word null 终止的示例,这个答案将是完美的。
  • @MarkRansom 我敢打赌我可以举一个例子来说明如何使word null 终止,这将使这个答案远非完美。哇哈哈哈哈哈哈哈哈。
  • 已添加@MarkRansom。
  • 现在完美了。谢谢。
【解决方案2】:

这个数组不是以空值结尾的。使其以空值终止的一种简单方法是从 string literal 初始化它,如下所示:

std::array<char, 5> a{"abcd"};

【讨论】:

  • 有趣的是std::array&lt;int, 5&gt; 不会默认将数组中的整数初始化为 0,但std::array&lt;char, 5&gt; 会默认将所有字符初始化为 0。这是为什么呢?
【解决方案3】:

下面的sn-p代码安全吗?

没有。它正在调用未定义的行为

它调用了 std::string 的第四个构造函数,该构造函数接受一个指向空终止字符串的指针。问题是,我不确定下面的word 是否为空终止。是吗?

不,不是。

假设您不想以空值终止数组,一个简单的解决方法是使用不同的std::string 构造函数,该构造函数将所需长度作为参数,例如:

std::array<char, 4> word{'a', 'b', 'c', 'd'};

int main()
{
    std::string p(word.data(), word.size());
    // more generally:
    // std::string p(word.data(), desired_length);
    return 0;
}

或者,您可以使用不同的 std::string 构造函数来代替迭代器,例如:

std::array<char, 4> word{'a', 'b', 'c', 'd'};

int main()
{
    std::string p(word.begin(), word.end());
    // more generally:
    // std::string p(word.begin(), word.begin() + desired_length);
    return 0;
}

无论哪种方式,您都不需要空终止符。

【讨论】:

  • 我开始考虑.data 的原因是因为我不想使用endbegin。为什么?好吧,我有一个包含 4 个非空字符和 46 个空终止符 (std::array&lt;char, 50&gt;) 的数组。这最终创建了一个长度为 50 的字符串,其中包含 46 个空终止符。当这个字符串是映射的键时,你会很糟糕......实际上,“abcd”(1 个空终止符)看起来与“abcd”(46 个空终止符)相同,但它们是完全不同的键到地图。 godbolt.org/z/MKPs7MW4v
  • @TeeZadAwk 在这种情况下,std::string p(word.data(), 4);std::string p(word.begin(), word.begin()+4); 会为您工作。
  • 是的,但我事先不知道数组内容的确切长度。换句话说,我得到了一个大小为 50 的数组,但我不确定是否所有内容都是空终止符,有些是空终止符,还是非空终止符。
  • @TeeZadAwk 您可以使用std::find() 检查数组中是否存在空终止符。如果是这样,从结果中减去begin() 以获得它的索引(或使用std::distance()),这就是你的长度。如果不存在,则使用数组的完整大小,例如:auto iter = std::find(word.begin(), word.end(), '\0'); size_t length = (iter != word.end()) ? (iter - word.begin()) : word.size(); std::string p(word.data(), length);
  • @TeeZadAwk 或者,您可以使用迭代器来简化,例如:std::string p(word.begin(), std::find(word.begin(), word.end(), '\0')); 如果找到空终止符,它将只复制到终止符,否则它将复制到末尾数组。
【解决方案4】:

如果您的目标是在 std::array 中使用 null 终止字符串 初始化 std::string,但不要超出范围,则可以使用 @987654322 @像这样:

std::string p{std::begin(word), std::find(std::begin(word), std::end(word), '\0')};

如果没有 null 终止符,它将初始化到第一个 null 终止符或数组的末尾。

【讨论】:

    猜你喜欢
    • 2020-03-22
    • 2012-06-16
    • 2012-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-23
    • 2021-03-19
    • 2017-05-29
    相关资源
    最近更新 更多