今天在微软家的strncpy_s函数上栽了跟头,记录一下

char *strncpy(char *strDest, const char *strSource, size_t count );
errno_t strncpy_s(char *strDest,  size_t numberOfElements, const char *strSource, size_t count);

简言之,在已经从strSource拷贝了多达count个非0字符后:

  • C标准库的strncpy函数不会strDest追加'\0'
  • 微软家的strncpy_s函数试图往strDest追加'\0'

细说

摘抄一下MSDN上关于strncpy函数的说明:

The strncpy function copies the initial count characters of strSource to strDest and returns strDest.
If count is less than or equal to the length of strSource, a null character is not appended automatically to the copied string.
If count is greater than the length of strSource, the destination string is padded with null characters up to length count. The behavior of strncpy is undefined if the source and destination strings overlap.

翻译过来:
strncpy函数拷贝strSource原始的count个字符到strDest,并且返回strDest
如果count小于等于strSource的长度,不会自动追加一个空字符到拷贝至的字符串。

再来看看MSDN上关于strncpy_s函数的说明:

These functions try to copy the first D characters of strSource to strDest, where D is the lesser of count and the length of strSource. If those D characters will fit within strDest (whose size is given as numberOfElements) and still leave room for a null terminator, then those characters are copied and a terminating null is appended; otherwise, strDest[0] is set to the null character and the invalid parameter handler is invoked, as described in Parameter Validation.
……

翻译过来:
这些函数[1]^{[1]}[1]尝试从 strSource 拷贝前D个字符到strDest,其中D是count和strSource中的较小者。如果strDest(它的大小由numberOfElements给出)能够装下那D个字符,并且仍然留有空间来放置一个空的结尾标志,那么那些字符会被拷贝并且会追加一个空的结尾标志;否则的话, strDest[0] 被设置为空字符,并且会调用无效参数处理机制,如 Parameter Validation中所述。

注[1]:在MSDN原文中"这些函数"代指一家子*ncpy_s形式的函数,strncpy_s函数是其中之一

从上面的两段说明可以看出,strncpystrncpy_s的行为是有着很大不同的。

在使用strncpy函数时我们可能习惯于把count设置为目的地址strDest的缓冲区大小,这是没有问题的,因为strncpy函数总是老老实实地就往目的地址拷贝恰好count个字符,如果拷贝过程到达了源字符串的结束标志'\0',后面直接用填充往目的地址若干个'\0',直到写入了满count个字符,否则如果拷贝了多达count个非0字符,就停止拷贝,不会往目的地址追加'\0'

strncpy_s函数则不一样,它总是试图往目的地址追加'\0',如果在调用strncpy_s函数时把count设置为目的地址strDest的缓冲区大小,可能会出错。因为如果源字符串字符个数(不计入结尾的'\0')大于等于count,那么strncpy_s函数发现:如果拷贝count个非0字符并且追加一个'\0',这个追加的'\0'其实就越界了,所以strncpy_s函数不会进行拷贝,并且会抛出异常。

所以在调用strncpy_s函数时,用来说明strDest缓冲区的大小的那个参数numberOfElements必须满足——
numberOfElements ≥\geq≥ 1+ min(count,strlen(strDest))

示例

已测试于VS2019

分析下面的示例程序

#include <stdio.h>
#include <string.h>int main()
{char buff[11] = "cccccccccc";       //buff内容为 cccccccccc\0strncpy(buff, "hello", 5);          //buff内容变为helloccccc\0printf("%s\n", buff);               //打印hellocccccstrncpy_s(buff, 6, "world", 5);     //buff内容为world\0cccc\0printf("%s\n", buff);               //打印worldstrncpy_s(buff, 5, "abcde", 5);      //抛出异常return 0;
}

刚开始buff缓冲区的内容为

偏移 0 1 2 3 4 5 6 7 8 9 10
内容 ‘c’ ‘c’ ‘c’ ‘c’ ‘c’ ‘c’ ‘c’ ‘c’ ‘c’ ‘c’ ‘\0’

第7行的strncpy函数调用拷贝’h’、‘e’、‘l’、‘l’、'o’共5个字符到buff,不会补'\0'
这时buff缓冲区的内容为

偏移 0 1 2 3 4 5 6 7 8 9 10
内容 ‘h’ ‘e’ ‘l’ ‘l’ ‘o’ ‘c’ ‘c’ ‘c’ ‘c’ ‘c’ ‘\0’

第8行的printf会打印helloccccc

第9行的strncpy_s函数调用拷贝了’w’、‘o’、‘r’、‘l’、'd’这5个字符串后,还追加了一个'\0',实际上是往buff写入了6个字节。
这时buff缓冲区的内容为

偏移 0 1 2 3 4 5 6 7 8 9 10
内容 ‘w’ ‘o’ ‘r’ ‘l’ ‘d’ ‘\0’ ‘c’ ‘c’ ‘c’ ‘c’ ‘\0’

第10行的printf会打印world

第11行的strncpy_s函数调用,由于abcde加上一个'\0'有6个字符,超过了指定的缓冲区大小5,所以strncpy_s不会进行拷贝,并且会抛出异常。


弹出窗口中"Buffer is too small"这句话也直接说明了,抛出这个异常是因为缓冲区太小了(要写入6个字符,而缓冲区大小为5)。

【C语言】strncpy函数和strncpy_s函数的不同!关于末尾追加\0相关推荐

  1. C语言中的字符函数和字符串函数

    目录 前言 1.常用函数介绍 1.1 strlen 1.2 stycpy 1.3 strcat 1.4 strcmp 1.5 strncpy 1.6 strncat 1.7 strncmp 1.8 s ...

  2. c语言strncpy函数定义,strncpy (Strings) – C 中文开发手册

    C 语言中文开发手册 strncpy (Strings) - C 中文开发手册 在头文件中定义 ​ ​ ​ (1) ​ char * strncpy(char * dest,const char * ...

  3. strcpy()、strncpy()、strlcpy()、strncpy_s()函数

    strncpy()函数 原型:extern char *strncpy(char *dest, char *src, int n);     用法:#include <string.h>  ...

  4. C语言——数组、字符串处理函数、strlen、strcpy和strncpy、strcat和strncat、strcmp和strncmp

    目录 一.数组 1.定义:类型 数组名[元素个数] 2.数组不能动态定义 3.如何访问数组中的元素:数组名[下标] 4.循环与数组的关系 5.数组的初始化 二.C99标准中的数组 三.字符串处理函数 ...

  5. c语言拷贝特定个数的字符串,C语言strncpy函数

    C语言strncpy函数教程 strncpy 是一种 C 语言的标准库函数,在拷贝时,我们可以指定最多复制 n 个字符.当源字符串的长度小于 n 时,目的字符串的剩余部分将用空字节填充. strncp ...

  6. C语言strncpy函数详解及其模拟实现

    char * strncpy ( char * destination, const char * source, size_t num ); strncpy函数是C语言中的内置函数之一,相较于str ...

  7. strcpy,strncpy和strncpy_s的区别 strncpy函数与memcpy函数

    首先说下strcpy strcpy()是依据源串的\0作为结束判断的,不检查copy先的Buffer的Size,如果目标空间不够,就有BufferOverflow问题. strncpy的原型为: ch ...

  8. (C语言)常用的字符串函数介绍(strcpy,strncpy,strcat,strncat,strcmp,strncmp,strchar,strlen)非常详细

    理解 strcpy,strncpy,strcat,strncat,strcmp,strncmp,strchar,strlen这些函数,可以帮助我们更好的对字符串进行操作,做到玩转字符串. 目录 1.s ...

  9. c语言strncpy函数定义,C 库函数 - strncpy()函数

    定义 函数原型: char *strncpy(char *dst, const char *src, size_t n); 函数说明: 函数strncpy从src指向的数组中最多复制n个字符(若数组中 ...

最新文章

  1. nginx location 配置详细解释
  2. 怒卸python3.4.1
  3. python 控制qq_最必要的最小建议集:写给刚入门编程(python)的同学
  4. 应用ADO.net得到表
  5. 判断IE版本与各浏览器的语句
  6. java 监控对象是什么_多线程-Java中的对象监视器是什么意思? 为什么要使用这个词?...
  7. 【收藏】RPM包制作和spec文件详解
  8. 学生管理系统----当然封装类型
  9. python下视频的包_Python——爬取包图网图片和视频
  10. C++ 一篇搞懂继承的常见特性
  11. 阿里云图片服务器OSS对象存储器使用方法(附详细步骤)
  12. visual studio 调试php,使用visual studio code调试php代码
  13. CTS测试中testYuvBurst[1]项
  14. 一个index.html怎么添加备案号,ICP备案号怎么添加到自己网页底部?
  15. 哪款视频压缩软件比较好用?
  16. 如何让EXCEL公式结果不显示#N/A、#VALUE!的错误
  17. 实现极致节能,维谛技术(Vertiv)有哪些特殊技能?
  18. 科研篇一:NeurIPS2019 分类整理-对抗样本Meta-Learning
  19. 避免论文查重小窍门五则
  20. 160809310袁韬淳

热门文章

  1. 洛谷3953:逛公园——题解
  2. PyQuery 简介
  3. 员工拒绝加班判赔1.8万事件!二审维持原判,理由来了…
  4. 基于javaweb+mysql的私人牙医管理系统(java+SpringBoot+html+layui+echarts+maven+mysql)
  5. ESLint语法检查--indent(缩进)规则
  6. mpvue - vant-weap小程序分包
  7. 如何为2D游戏做出空间感和3D感?
  8. 如何提升设计的层次感
  9. ios高版本app成功砸壳之kali使用frida-ios-dump砸壳
  10. 和python哪个容易胖_吃肉和吃饭,哪个更容易长胖?