其实,用C/C++做开发的童鞋,对sprintf不会陌生,对该函数的一些问题,一直想好好总结下:

如果第2个format(格式)参数中用%指定的后续参数个数与实际参数必须一致,否则可能会出各种问题。所谓一致是严格一致,看几个例子:

1. 参数类型不匹配

如果你用的%d,对应的实参却用double,将得到错误的结果,而且更为严重的是,如果该参数后还有别的参数,将影响后面的参数解析:

char buf[1024];double dV = 123.0;
int iLen = sprintf( buf, "Test:  %d, not one %d\n", dV, 1);std::cout << buf;

并不会输出期望的结果:Test:  123, not one 1

我在VS2013下得到的输出是: Test:  0, not one 1079951360

如果我们知道函数调用和参数传递的机理,就会明白,sprintf 期望format参数后接2个int型参数(都是4字节的),但却给了个double参数和一个常数,我们知道double是8字节的,所以double就被分为了2个int,而后面的常数1压根就没用上,所以结果不可能正确。

结果要正确,必须将double参数强转成int:

int iLen = sprintf( buf, "Test:  %d, not one %d\n", (int)dV, 1);

2. 参数数目不匹配

format中指定的参数数目与实际的数目不一致时,也得不到正确的结果:

int iLen = sprintf( buf, "Test:  %d, not one %d\n", 1);    // 实参少1个

VS2013下得到的输出:Test:  1, not one -84618255

其实后面显示的数是随机的,就是函数调用栈实参1后面的一个4字节数,这个例子不会导致宕机,因为第2个实参取的是栈上的随机数(未初始化数)。

3. 参数类型不匹配

如果format参数中有%s,则对应的实参一定得给对了,否则极其可能宕机:

char buf[1024];double dV = 123.0;
int iLen = sprintf( buf, "Test:  %s, not one %d\n", dV, 1);std::cout << buf;

在Debug模式下,将断点设置在最后一行,将会发现调用栈完全不对了,因为sprintf将dV的值当字符串地址看待,所以宕掉

char buf[1024];std::string str = "hello";
int iLen = sprintf( buf, "Test:  %s, not one %d\n", str, 1);std::cout << buf;

这个也不会输出正常结果, 会把str对象(copy的对象)的空间当作字符串地址

VS2013下得到的输出:  Test:  (null), not one -858993460 (还算幸运,没宕机)
sprintf不会帮你做字符串转换,你的主动告诉它。

最后,第1个缓冲区参数,需要有足够的空间,否则很容易越界导致各种问题。

sprintf_s在缓冲区后加了个缓冲区大小参数,VS的实现会将缓冲区按缓冲区大小参数memset,所以,如果缓冲区大小参数不正确,又将可能导致新的问题--越界

原文链接:https://blog.csdn.net/Joal_zhu/article/details/38681583

字符串函数sprintf / sprintf_s 容易出错的地方相关推荐

  1. C 字符串函数 sprintf()、snprintf() 详解

    一.sprintf() 函数详解 在将各种类型的数据构造成字符串时,sprintf 的强大功能很少会让你失望. 由于 sprintf 跟 printf 在用法上几乎一样,只是打印的目的地不同而已,前者 ...

  2. Linux C 字符串函数sprintf()和snprinttf()

    sprintf()函数详解 int sprintf( char *buffer, const char *format , - ); 函数说明:将格式化的字符串输入到buffer中. 函数返回值:bu ...

  3. PHP学习记录(字符串函数)

    字符串常用函数 获取字符串长度函数 /* * strlen函数 * int strlen($var) * 获取字符串或数字的长度 */ $a = 'hello, woRld'; $b = '王昭'; ...

  4. 如果$.ajax函数迟迟得不到响应,那么最有可能出错的地方是请求参数写错了

    如下的$.ajax函数 $.ajax({url: url,// 请求的地址data:{id:id,pieceId:pieceId,pieceDesc:pieceDesc,actualStock:act ...

  5. C语言再学习 -- 字符串和字符串函数

    最近身体很不给力,很乏累!白天没精神,晚上睡不着,心情还很烦躁.看书都有点看不下去的样子,到了C语言最难掌握的部分了,数组.指针.字符串.硬着头皮看书总结吧. 一.字符串 1.字符串介绍 字符串是以空 ...

  6. c字符串函数实现(1)---strncpy

    strncpy原型:char* strncpy(char* dest,const char* src,size_t count); 函数说明:1.当count <= strlen(src)+1( ...

  7. PHP常用字符串函数小结

    最近面试被这个面到吐血,特地来fork一些. 来源:https://www.jb51.net/article/145084.htm 一.判断类型的函数 is_bool() //判断是否为布尔型 is_ ...

  8. PHP字符串函数大全

    PHP字符串函数大全 AddSlashes: 字符串加入斜线. bin2hex: 二进位转成十六进位. Chop: 去除连续空白. Chr: 返回序数值的字符. chunk_split: 将字符串分成 ...

  9. C语言之字符串探究(五):N系列字符串函数——strncpy、strncat、strncmp

    相关博文:C++之char和string字符串类探究 相关博文:C语言之数组探究(一):定义.大小.初始化.访问和三要素 相关博文:C语言之字符串探究(一):字符串与字符数组 相关博文:C语言之字符串 ...

  10. printf函数,fprintf函数,sprintf函数

    printf 函数作用:格式化输出函数, 一般用于向标准输出设备按规定格式输出信息. 原型 extern int printf(const char *format,...); 用法 //以下程序用于 ...

最新文章

  1. mysql悲观锁和乐观锁
  2. Asp.Net MVC中Action跳转小结
  3. 【计算机网络】数据链路层 : 差错控制 ( 纠错编码 | 海明码 | “海明码“ 原理 | “海明码“ 工作流程 | 确定校验啊位数 | 确定校验码和数据位置 | 求校验码值 | 检错纠错 )★
  4. http经典书籍--http权威指南
  5. linux echo 变量 字符串,echo命令 – 输出字符串或提取Shell变量的值
  6. Java里的字符串, String类简单介绍.
  7. 【bzoj3879】SvT 后缀数组+倍增RMQ+单调栈
  8. 第四范式携手智源研究院 共推全球最大智能模型应用发展
  9. java中 flush()方法
  10. mysql改原始密码mac_MAC版修改MySQL初始密码的方法
  11. Python学习day2 while循环格式化输出运算符
  12. aix创建oracle表空间,Oracle for AIX基于裸设备的表空间扩充步聚
  13. 大数据Hadoop之——任务调度器Oozie(Oozie环境部署)
  14. 计算机2.0培训心得,2020信息技术2.0培训心得
  15. 这一本《电子工程师技术手册》,你要不要?
  16. 金山打字测试一分钟软件,金山打字2006——一款打字练习及测试软件.doc
  17. B站的热门视频要怎么同时批量下载保存到本地电脑中
  18. java实战--GC终极总结
  19. 看aps高级排产如何实现生产计划智能排产
  20. pdf转换成word转换器免费版

热门文章

  1. rc.local文件开机不执行
  2. java 求集合真子集_干货 | 集合与函数概念知识点总结
  3. 电脑网络禁用了怎么恢复_Tenorshare UltData for Mac(iOS数据恢复备份软件)v9.4.1中文激活版_软件动态论坛...
  4. A. Death Note
  5. HDU3853:LOOPS
  6. C语言,使用结构体读入两个在同一年的日期,判断日期是否合法,并计算两个日期之间相差的天数。结构体定义如下:...
  7. [C++]类的继承与派生
  8. TFS无法连接:TF31002
  9. cvErode() 形态腐蚀(可多次)
  10. 索尼便携式无线服务器,WF-SP900体验报告:2018索尼真无线产品中的顶端存在