[英]strncpy documentation question
关于strncpy
: http : strncpy
,它提到了以下内容:
没有空字符隐式附加到目标的末尾,因此如果源中的C字符串的长度小于num,则目标将仅以空值终止。
这句话是什么意思?
这意味着,例如,如果源字符串是20个字符加上空终止符并且strncpy
指定少于21个字符,则目标字符串将不会附加空值。
这是因为它的工作方式: strncpy
保证它将准确写入N个字节,其中N是传入的长度值。
如果源字符串的长度(无空字节)小于该字符串,则它将使用空值填充目标区域。 如果它等于或大于,则不会将null添加到目标。
这意味着它在技术上可能不是你得到的C字符串。 这可以通过以下代码解决:
char d[11]; // Have enough room for string and null.
strncpy (d, s, 10); // Copy up to 10 bytes of string, null the rest.
d[10] = '\0'; // Then append null manually in case s was too long.
您分配11个字节(数组索引0..10),复制到10(索引0..9)然后将第11个(索引10)设置为null。
这是一个图表,显示了使用strncpy (d, s, 10)
将各种大小的字符串写入10个字符区域的三种可能性.
表示空字节:
s d
------------- ----------
Hello. Hello.....
Hello Fred. Hello Fred
Hello George. Hello Geor
请注意,在第二种和第三种情况下,不会写入空字节,因此,如果将d
视为字符串,则可能会对结果感到失望。
字符串"foo"
有3个字符+ 1个空终止符(它存储为"foo\\0"
),总长度为4.如果你用n=3
(或更少)调用strncpy
,它将不会附加一个null-终止符到目标字符串的末尾,但只复制"foo"
。 由于缺少表示字符串结尾的空终止符,因此尝试打印结果字符串将导致未定义的行为。
您必须非常小心这一点,并且要么传递大于最大源的n
,要么自己添加null-terminator。
这意味着它复制源字符串的终止空值,但如果源字符串不适合目标,则不会添加终止空值。
在作为char
数组存储的C字符串中,它们以空值终止,这意味着它们在末尾附加了一个额外的0
,这标志着字符串的结尾,以后可以用来计算字符串的长度。 所以字符串"hello"
在内存中看起来像这样:
char hello[] = {'h', 'e', 'l', 'l', 'o', 0};
通常,复制字符串时,也应复制null
字符。 所以字符串缓冲区所需的内存是它的长度+ 1(例如(strlen(hello) + 1) * sizeof(char)
)。
函数strncpy
允许您只复制尽可能多的字符以适合提供的缓冲区。 如果您提供的缓冲区不足以容纳额外的null
,则不会添加它。 或者,如果字符串被剪切,它将不会以空值终止。
char hello[] = "hello"; // 5 characters, 6 bytes long
char hel[3];
strncpy(hel, hello, 3); // hel is {'h', 'e', 'l'}
调用strncpy
后应该总是小心,因为结果可能不是有效的C字符串。 如果字符串不是以null结尾,则无法知道其长度,并且大多数字符串操作函数将失败或将执行意外操作。
这意味着只有num
个字节将从源缓冲区复制到目标缓冲区; 因此,如果源字符串长度大于或等于num
,则不会复制终止NULL字节,并且结果将不具有NULL终止字节,这是危险的。
建议使用strlcpy代替。
strncpy()
的语义,即使在上面的C ++参考中被精确解释,也被广泛误解。 此函数的行为是违反直觉且容易出错的。
为了避免在使用它或进一步开发过程中出现问题,当维护者误读代码并添加更多的漏洞时,有一个简单的解决方案: 永远不要使用这个功能 。
您可以在Bruce Dawson的这篇文章中阅读有关此内容的更多详细信息。
回答你的问题:如果源字符串长于作为第三个参数传递的大小(通常对应于目标缓冲区的大小),则该函数会将大小字符复制到目标,并且这些字符之间不会出现空字节。 调用strlen(destination);
然后将调用未定义的行为,因为它将尝试读取超出数组末尾的内容,直到找到空终止符。 这种特定的行为使得strncpy
容易出错。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.