snprintf函数是sprintf函数的安全版本,因为它在调用的时候需要指定缓冲区的最大尺寸,这样可以有效避免缓冲区的益处。
如果写入的字符串尺寸大于size-1,那么后边的字符串将被丢弃,但是依旧会统计进长度中(返回值)。
format参数后边的额外参数数量是由format决定的,具体用法请参考printf函数中格式化占位符的解释。
将可变个参数(...)按照format格式化成字符串,然后将其复制到str中
(1) 如果格式化后的字符串长度 < size,则将此字符串全部复制到str中,并给其后添加一个字符串结束符('\0');
(2) 如果格式化后的字符串长度 >= size,则只将其中的(size-1)个字符复制到str中,并给其后添加一个字符串结束符('\0')
函数返回值:若成功则返回欲写入的字符串长度,若出错则返回负值。 --------------------------------------------
函数说明:最多从源串中拷贝n-1个字符到目标串中,然后再在后面加一个0。所以如果目标串的大小为n 的话,将不会溢出。
二、函数原型
#include<stdio.h>int snprintf(char *str, size_t size, const char *format, ...);
三、参数解析
参数 | 含义 |
str | 指向存放结果字符串的缓冲区 |
size | 1.限定缓冲区最大可写入的字节数 2.字符串最多可以拥有size-1 个字符串,最后一个空位用于存放‘\0' 3.size_t 被定义为无符号整型 |
format | 格式化字符串 |
... | 可选参数,具体请参考printf函数文档 |
四、返回值
如果指定size的缓冲区足够存放写入的字符,返回值是实际写入的字符数(不包含表示字符串结束的‘\0’);
如果函数调用失败,返回值是一个负数。
五、功能 :合并字符串、整形变量转换成字符串
(1)将数字变量转换为字符串。
(2)得到整型变量的16进制和8进制字符串。
(3)连接多个字符串。
六、注意
1.试图写入字符的数量超过size,并不会导致错误发生,只是超过部分被丢弃。2.只有当返回值小于size 且非负数,才证明字符串被完全写入。
举例:
1、整型数字转换为字符串
#include<stdio.h>
int main()
{
char testdstchar[10]={0};
int j = 12;
snprintf(testdstchar,sizeof(testdstchar), "%d", j);
printf("%s",testdstchar);
return 0;
}
输出:12
2、浮点型转换为字符串
#include<cstdio>
#include<string>
#include<iostream>
using namespace std;
int main() {
char a[10];
double i = 12.532423;
snprintf(a, sizeof(a), "%lf", i);
cout << a << endl;
snprintf(a, sizeof(a), "%0.2lf", i); //设置转换的精度
cout << a << endl;
}
输出结果为:
12.532423
12.53
3、拷贝字符串
#include<cstdio>
#include<string>
#include<iostream>
using namespace std;
int main() {
char a[10];
char c[] = "dskcdsvkjgch";
snprintf(a, sizeof(a), "%s", c); //以a的数组长度作为转换的位数,则最多拷贝9为,最后加\0。
cout << a << endl;
snprintf(a, sizeof(c), "%s", c); //以c的字符长度作为转换的位数,系统会自动将a的数组长度调整到刚好能匹配c的字符。
cout << a << endl;
}
输出结果:
dskcdsvkj
dskcdsvkjgch
使用snprintf的另一个好处是可以实现字符串的连接,再加上其相对安全的功能,strcat基本就可以抛弃了
#include<cstdio>
#include<string>
#include<iostream>
using namespace std;
int main() {
char a[10];
char c[] = "dskc";
snprintf(a, sizeof(a), "%s", c); //以数组名作为参数,实际上是从数组 第一位开始拷贝字符。
cout << a << endl;
snprintf(a+4, sizeof(a), "%s", c); //实现连接,要注意连接开始的位置,之前a的前四位有字符,因此从第五位开始,对应数组脚标4,小于4,则之前的字符被覆盖,大于4,则a[4]为'\0';
cout << a << endl;
}
输出结果:
dskc
dskcdskc
需要注意的几点:
1、函数的返回值
snprintf的返回值是欲写入的字符串长度,而不是实际写入的字符串度。
#include<stdio.h>
int main()
{
char testdstchar[10]={0};
int j = 12;
int ret = 0;
ret = snprintf(testdstchar, 5,"123456789");
printf("%d|%s",ret,testdstchar);
return 0;
}
输出: 9|1234
#include<stdio.h>
int main()
{
char testdstchar[10]={0};
int j = 12;
int ret = 0;
ret = snprintf(testdstchar, 11,"12345678901234567890");
printf("%d|%s",ret,testdstchar);
return 0;
}
输出:20|1234567890
2、利用snprintf函数来提前获取需要的内存空间大小.
按如下格式调用:int ret = snprintf(NULL,0,"%s%d","test", 123); //结果ret为7
即设置第一二个参数分别为NULL和0,获得的ret就为实际需要的内存空间大小。这对于打印长度不可预知的字符串比较有效,便于我们合理分配空间,既不浪费又不产生截断。
(1)如果格式化后的字符串长度 < size,则将此字符串全部复制到str中,并给其后添加一个字符串结束('\0');
(2)如果格式化后的字符串长度 >= size,则只将其中的(size-1)个字符复制到str中,并给其后添加一个字符串结束符('\0')
3、snprintf处理原始和目标缓冲区重叠时,会出现不可预期的结果。
#include<stdio.h>
int main()
{
char testdstchar[10]="abcdefg";
int j = 12;
int ret = 0;
ret = snprintf(testdstchar, 10,"%s,hello",testdstchar);
printf("%d|%s",ret,testdstchar);
return 0;
}
输出:6|,hello