You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为什么strncpy()在目标缓冲区小于源串但足够容纳待拷贝子串时输出乱码?

strncpy()乱码问题根本原因

你的猜测是错的,strncpy()不会先拷贝完整源串再截断,它确实最多只拷贝你指定的n个字节,乱码的核心原因是你没搞懂strncpy()的设计逻辑和C语言字符串的终止规则。

strncpy()的真实行为规则

这个函数从设计之初就不是“安全版strcpy”,它最早是为了操作UNIX文件系统的定长路径字段设计的,行为非常反直觉:

  • 如果源字符串长度小于指定拷贝长度n:strncpy()会拷贝完源串的所有内容(含末尾的\0),然后把目标缓冲区剩下的n个字节全部填\0
  • 如果源字符串长度大于等于指定拷贝长度n:strncpy()只会精确拷贝n个字节,绝对不会自动在拷贝内容末尾追加\0字符串终止符

为什么会出现你看到的现象

C语言中所有字符串处理函数(printf("%s")、strlen()等)判断字符串结束的唯一标记是\0字符,只要没碰到\0,函数就会一直往后读内存,不管是不是属于当前字符串的范围,这就是你看到乱码、strlen结果不对的核心原因。

  • 你定义的str1、str2是栈上的局部数组,没有手动初始化,数组里存的是程序运行时栈上遗留的随机垃圾值,不会自动清零。
  • 你给str2拷贝3字节时输出正常,完全是巧合:拷贝完3个字符后,str2数组第4个字节(下标为3的位置)的垃圾值刚好是\0,字符串函数读到这里就停了,看起来结果正确,本质是未定义行为,换个编译选项、换个运行环境随时可能出问题。
  • 你给str1拷贝4字节时输出乱码:拷贝完4个字符后,str1数组从第5个字节(下标为4的位置)开始都是随机垃圾值,没有碰到\0,strlen和printf会越界读取后面的栈内存,把随机值一起打出来,就是你看到的乱码,读到的长度也是随机的。
  • 你把str1改成长度20时输出正常,同样是巧合:只是这个时候数组后面的内存值刚好是\0而已,不是代码逻辑正确,依然属于未定义行为。

正确修复方式

只要你使用strncpy()时指定的拷贝长度n小于等于源串长度,就必须手动在拷贝的内容末尾追加\0终止符,不要赌内存里的残留值。修正后的代码片段如下:

// str1操作
strncpy(str1, argv[1], 4); // 向str1拷贝4字节
str1[4] = '\0'; // 手动追加字符串终止符,这行必须加
printf("仅拷贝4字节 -> sizeof(str1) = %li, "
       "strlen(str1) = %li, str1 = %s\n", sizeof(str1), strlen(str1), str1);

// str2操作
strncpy(str2, argv[1], 3); // 向str2拷贝3字节
str2[3] = '\0'; // 手动追加字符串终止符
printf("仅拷贝3字节 -> sizeof(str2) = %li, "
       "strlen(str2) = %li, str2 = %s\n", sizeof(str2), strlen(str2), str2);

加完这两行补终止符的代码,不管你把str1、str2的长度设为10还是其他大于拷贝长度+1的值,输出都会稳定符合预期,不会再出现乱码。


内容的提问来源于stack exchange,提问作者Coder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 00:39:18