插入没有空终止符空间的字符串是否安全?

Is it Safe to strncpy Into a string That Doesn't Have Room for the Null Terminator?

本文关键字:字符串 是否 安全 空间 终止 插入      更新时间:2023-10-16

请考虑以下代码:

const char foo[] = "lorem ipsum"; // foo is an array of 12 characters
const auto length = strlen(foo); // length is 11
string bar(length, ''); // bar was constructed with string(11, '')
strncpy(data(bar), foo, length);
cout << data(bar) << endl;

我的理解是,string总是用隐藏的空元素分配的。如果是这种情况,那么bar真的分配了 12 个字符,第 12个字符是一个隐藏的'',这是完全安全的......如果我错了,那么cout将导致未定义的行为,因为没有空终止符。

有人可以帮我确认吗?这合法吗?


关于为什么要使用 strncpy 而不是只使用 string(const char*, const size_t) 构造函数,有很多问题。我的目的是让我的玩具代码接近我包含vsnprintf的实际代码。不幸的是,即使在这里得到了很好的答案,我发现vsnprintf的行为与strncpy不同,我在这里问了一个后续问题:为什么 vsnprintf 没有像 strncpy 那样写入相同数量的字符?

这是安全的,只要您将[0, size())字符复制到字符串中即可。 每 [基本字符串]/3

在所有情况下,[data(), data() + size()] 都是有效范围,data() + size()指向值为 charT() 的对象("空终止符"),size() <= capacity() true

因此,string bar(length, '')为您提供一个size()为 11 的字符串,末尾有一个不可变的 null 终止符(实际大小总共为 12 个字符)。 只要您不覆盖该空终止符,或尝试写过它,您就可以了。

这里有两件不同的事情。

首先,strncpy在此实例中添加额外的(11 个非元素要复制到大小为 11 的字符串中)。答案是否定的:

最多将 src 指向的字节字符串的计数字符(包括终止空字符)复制到 dest 指向的字符数组。

如果在复制整个字符串 src 之前达到计数,则生成的字符数组不会以 null 结尾。

所以电话完全没问题。

然后data()给你一个正确的结尾字符串:

c_str() 和 data() 执行相同的功能。(自C++11起)

所以看来对于C++11来说,你是安全的。字符串是否分配了额外的似乎没有在文档中指示,但 API 很清楚您正在做的事情完全没问题。

您已经分配了一个 11 个字符的std::string。您不会尝试读取或写入任何内容,因此该部分将是安全的。

所以真正的问题是你是否搞砸了字符串的内部结构。既然你没有做任何不允许的事情,那怎么可能?如果字符串需要在内部保留一个 12 字节缓冲区,并在末尾填充空填充以履行其协定,则无论您执行什么操作,都是这种情况。

是的,根据字符 * strncpy(char* destination, const char* source, size_t num) 它是安全的:

从字符串中复制字符

将源的第一个字符数复制到目标。如果在复制 num 个字符之前找到源 C 字符串的末尾(由 null 字符表示),则目标将填充零,直到总共写入 num 个字符为止。