都知道,sprintf,snprintf是printf函数族的一员,只是它的输出对象是一个字符串缓冲区,而不是stdout或者文件。所以sprintf,snprintf很适合用来生成自己的格式化参数,易于解析。但是要注意的是关于字符串结束的问题,假设有这样的程序
#include<....>
int main(int argc,char *argv[]){
int len;
int i=1;
char buffer[128];
while(i<argc){
len=strlen(argv[i]);
if(len>=128)
exit(1);
snprintf(buffer,len,"%s",argv[i]);
i++;
}
printf("%s",buffer);
fflush(stdout);
return 0;
}
上面这个程序正确吗?能使用printf函数输出buffer字符串吗?
显然,程序是正确的,但是运行的结果是:不能输出字符串buffer!
使用gdb调试,假设,传递一个参数“hello",在gdb中查看len的值为5,正确,查看snprintf执行后,buffer的内容为"hell/000/000..."。证么回事?少了一个o,而且有正确的字符串结束符'/0'。-----这是问题1
修改上面的snprintf语句为:
snprintf(buffer,len+1,"%s",argv[i]);
然后使用gdb调试,可以看到buffer的内容为"hello/000/000..."
内容正确了,但是为什么printf("%s/n",buffer)依然不能输出?----问题2
然后将snprintf修改为:
snprintf(buffer,len+1,"%s/n",argv[i]);
使用gdb调试,可以看到buffer的内容为"hello/000/000...",和上面的一样,但是同样不能打印出字符串buffer!----------问题3
然后将snprintf修改为:
snprintf(buffer,len+2,"%s/n",argv[i]);
运行程序,发现可以打印出字符串buffer了,使用gdb调试
发现buffer的内容为"hello/n/000/000...",---------问题4
现在来分析一下上面的几个问题:首先为什么snprintf将格式化字符串输出到buffer时,会少掉最后一个字符(问题1,2,3),查看snprintf的manpage可以看到
size的大小其实是包含了最后一个字符结束符的大小,所以输出时会输出字符串的前size-1个字符,然后加上一个字符串结束符'/0'。那么问题4是:为什么字符串没有'/n'符号就不能打印出来呢?这个没道理啊。其实是终端显示的问题,如果最后一行不换行的话,将会和PS1(命令提示符)混合,根本就看不到输出的效果,你可以使用如下最简单的语句来测试:
printf("hello");