memmove处理字符串时第三个参数(strlen/strlen+1)的最佳实践问询
关于memmove第三个参数使用strlen(s)还是strlen(s)+1的疑问解答
好问题!这两种写法看起来结果一致,但背后的可靠性天差地别,咱们一步步拆解:
先看你的测试场景
先把你的代码整理并修正一处拼写错误(sting2→string2):
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <errno.h> int main() { char string1[20] = "Hello World"; char string2[20] = "Hello World"; printf("\nstring1=\"%s\"\n", string1); memmove(string1, string1 + 6, strlen(string1) + 1); printf("\nstring1 after memmove \"%s\" using strlen(string1) + 1\n", string1); printf("\nstring2=\"%s\"\n", string2); memmove(string2, string2 + 6, strlen(string2)); printf("\nstring2 after memmove \"%s\" using strlen(string2)\n", string2); return 0; }
程序输出:
string1="Hello World"
string1 after memmove "World" using strlen(string1) + 1string2="Hello World"
string2 after memmove "World" using strlen(string2)
为什么两种写法看起来结果一样?
你的测试里string2是大小为20的字符数组,初始化后"Hello World"只占前11个字节(10个字符+1个\0),剩下的9个字节会被自动初始化为\0。当你用strlen(string2)(值为11)作为memmove的长度时:
- 从
string2+6(指向'W')开始复制的11个字节里,前5个是'W','o','r','l','d',后面6个都是原数组自带的\0 - 复制到
string2开头后,World紧接着就是\0,printf遇到终止符就停止输出,所以看起来和strlen(s)+1的效果一致——但这完全是依赖数组额外空间的巧合。
两种写法的本质区别
strlen(s) + 1:这是复制合法C字符串的标准写法。strlen(s)返回的是字符串中有效字符的个数(不包含终止符\0),加1后明确包含了末尾的\0,确保复制后的结果是一个完整、合规的C字符串,无论目标数组的剩余空间多少,都能保证字符串有正确的终止符。strlen(s):这种写法没有复制终止符\0,能正常工作全靠数组额外的\0兜底。如果把string2改成刚好容纳"Hello World"的大小(char string2[11] = "Hello World";),memmove复制11字节后,string2末尾不会有\0,printf会越界读取内存直到遇到\0,这属于未定义行为,可能输出乱码甚至程序崩溃。
最佳实践总结
- 如果你要复制的是**需要保持C字符串特性(必须以
\0结尾)**的内容,一定要用strlen(source_ptr) + 1作为memmove的第三个参数,这是可靠、可移植的写法。 - 如果你只是复制一段二进制数据(不是C字符串),则根据实际需要复制的字节数来指定长度,此时不需要加1。
内容的提问来源于stack exchange,提问作者GoinOff
相关产品推荐
相关产品推荐

