c strncpy null terminated or not
我正在阅读这份文件,上面写着:
1
| char *strncpy(char *destination , const char *source , size_t num ); |
Copy characters from string
Copies the first num characters of source to destination. If the end of the source C string (which is signaled by a null-character) is found before num characters have been copied, destination is padded with zeros until a total of num characters have been written to it.
No null-character is implicitly appended at the end of destination if source is longer than num. Thus, in this case, destination shall not be considered a null terminated C string (reading it as such would overflow).
destination and source shall not overlap (see memmove for a safer alternative when overlapping).
但是我对这个说法感到困惑:
in this case, destination shall not be considered a null terminated C string (reading it as such would overflow)
由于如果num > strlen(source),它将以'\0'结尾,因此'\0'实际上是字符串中的空(终止)字符,为什么不将其视为以空终止的C字符串?
我已编写以下代码进行验证:
1 2 3 4 5 6 7 8
| char from [] = { 'h', 'e', 'l', 'l', 'o', '\0' };
char to [1024];
for (int i = 0; i < 1024; i ++) {
to [i ] = 'e';
}
strncpy(to , from , 1024);
printf("from %s
", from ); |
它在以下输出中正常工作:
-
strncpy:只是不使用它。
-
缺少\0的地方是strlen(source) > num,所以我认为您只是有一个简单的误解-尝试使用strncpy(to, from, 2);。
谈论的是strlen(source)> num的情况。它只会复制num个字符,都不是NUL,也不会添加NUL。
-
...并确保使用NUL终止符,请使用strlcpy而不是strncpy。
如果src的前len个字节中存在空终止符,则strncpy(dst, src, len)仅向dst添加空终止符。您的代码似乎可以正常工作,因为数组to[]后可能有或没有空字符。更好的测试是:
1 2 3 4 5
| char source [] ="source";
char dest [] ="destination";
strncpy(dest , source , 6);
printf("%s
", dest ); |
结果应为:
如果改为写strncpy(dest, source, 7),则输出仅为单词source。
strncpy()的语义,即使在上面的C ++参考文献中进行了精确解释时,也被普遍误解了。此功能的行为是违反直觉的,并且容易出错。
为了避免在使用它或进一步开发过程中出现问题,当维护人员会误读代码并添加更多的小错误时,有一个简单的解决方案:永远不要使用此功能。
您可以在Bruce Dawson的这篇文章中阅读有关此内容的更多详细信息。
要回答您的问题:如果源字符串长于作为第三个参数传递的大小(通常对应于目标缓冲区的大小),则该函数会将大小字符复制到目标,并且这些字符中将不存在空字节。然后,调用strlen(destination);将调用未定义的行为,因为它将尝试读取数组末尾之外的内容,直到找到空终止符为止。这种特定的行为使strncpy易于出错。
-
@EvilTeach:我更新了答案。阻止新手使用此易于出错的功能非常重要。我已经看到过很多滥用案例,即使是经验丰富的程序员也是如此。它充当着通用的错误吸引者。
-
这是最好的答案。可惜的是,从不使用此功能不能在红色和黑色之间闪烁。
-
我会将strtok,atoi,atof和整个scanf系列添加到要避免的功能列表中。
-
@EvilTeach:我同意strtok和scanf。 atoi和atof不提供错误检查,但问题较少。 feof()在列表中也相当高,sprintf()应该替换为snprintf(),char应该默认为无符号,必须使用2s补码,以及8/16/32 /和64位整数类型, IEEE浮点运算……这会使C变得简单得多。
-
@EvilTeach:feof()在while (!feof(fp))中几乎被系统地滥用。默认情况下,char签名与getc()不一致,返回的是unsigned char类型加EOF,strcmp()的值,并将字符串作为unsigned char的数组进行比较,并且将中的函数对负的值。