sprintf和printf的区别范文word版 18页.docx
《sprintf和printf的区别范文word版 18页.docx》由会员分享,可在线阅读,更多相关《sprintf和printf的区别范文word版 18页.docx(15页珍藏版)》请在冰豆网上搜索。
sprintf和printf的区别范文word版18页
本文部分内容来自网络整理,本司不为其真实性负责,如有异议或侵权请及时联系,本司将立即删除!
==本文为word格式,下载后可方便编辑和修改!
==
sprintf和printf的区别
篇一:
c语言printf的用法
sprintf
printf可能是许多程序员在开始学习C语言时接触到的第二个函数(我猜第一个是main),说起来,自然是老朋友了,可是,你对这个老朋友了解多吗?
你对它的那个孪生兄弟sprintf了解多吗?
在将各种类型的数据构造成字符串时,sprintf的强大功能很少会让你失望
由于sprintf跟printf在用法上几乎一样,只是打印的目的地不同而已,前者打印到字符串中,后者则直接在命令行上输出这也导致sprintf比printf有用得多所以本文着重介绍sprintf,有时也穿插着用用pritnf
sprintf是个变参函数,定义如下:
intsprintf(char*buffer,constchar*format[,argument]...);
除了前两个参数类型固定外,后面可以接任意多个参数而它的精华,显然就在第二个参数:
格式化字符串上
printf和sprintf都使用格式化字符串来指定串的格式,在格式串内部使用一些以%开头的
格式说明符(formatspecifications)来占据一个位置,在后边的变参列表中提供相应的变量,最终函数就会用相应位置的变量来替代那个说明符,产生一个调用者想要的字符串
格式化数字字符串
sprintf最常见的应用之一莫过于把整数打印到字符串中,所以,spritnf在大多数场合可以替代itoa如:
//把整数123打印成一个字符串保存在s中
sprintf(s,"%d",123);//产生"123"
可以指定宽度,不足的左边补空格:
sprintf(s,"%8d%8d",123,4567);//产生:
"1234567"
当然也可以左对齐:
sprintf(s,"%-8d%8d",123,4567);//产生:
"1234567"
也可以按照16进制打印:
sprintf(s,"%8x",4567);//小写16进制,宽度占8个位置,右对齐
sprintf(s,"%-8X",4568);//大写16进制,宽度占8个位置,左对齐
这样,一个整数的16进制字符串就很容易得到,但我们在打印16进制内容时,通常想要一
种左边补0的等宽格式,那该怎么做呢?
很简单,在表示宽度的数字前面加个0就可以了
sprintf(s,"%08X",4567);//产生:
"000011D7"
上面以%d进行的10进制打印同样也可以使用这种左边补0的方式
这里要注意一个符号扩展的问题:
比如,假如我们想打印短整数(short)-1的内存16进制表
示形式,在Win32平台上,一个short型占2个字节,所以我们自然希望用4个16进制数字来打印它:
shortsi=-1;
sprintf(s,"%04X",si);
产生FFFFFFFF,怎么回事?
因为spritnf是个变参函数,除了前面两个参数之外,后面的
参数都不是类型安全的,函数更没有办法仅仅通过一个%X就能得知当初函数调用前参数压栈
时被压进来的到底是个4字节的整数还是个2字节的短整数,所以采取了统一4字节的处理方式,导致参数压栈时做了符号扩展,扩展成了32位的整数-1,打印时4个位置不够了,就把32位整数-1的8位16进制都打印出来了如果你想看si的本来面目,那么就应该让编译器做0扩展而不是符号扩展(扩展时二进制左边补0而不是补符号位):
sprintf(s,"%04X",(unsignedshort)si);
就可以了或者:
unsignedshortsi=-1;
sprintf(s,"%04X",si);
sprintf和printf还可以按8进制打印整数字符串,使用%o注意8进制和16进制都不会打
印出负数,都是无符号的,实际上也就是变量的内部编码的直接的16进制或8进制表示
控制浮点数打印格式
浮点数的打印和格式控制是sprintf的又一大常用功能,浮点数使用格式符%f控制,默认保
留小数点后6位数字,比如:
sprintf(s,"%f",3.1415926);//产生"3.141593"
但有时我们希望自己控制打印的宽度和小数位数,这时就应该使用:
%m.nf格式,其中m表
示打印的宽度,n表示小数点后的位数比如:
sprintf(s,"%10.3f",3.1415626);//产生:
"3.142"
sprintf(s,"%-10.3f",3.1415626);//产生:
"3.142"
sprintf(s,"%.3f",3.1415626);//不指定总宽度,产生:
"3.142"
注意一个问题,你猜
inti=100;
sprintf(s,"%.2f",i);
会打出什么东东来?
100.00?
对吗?
自己试试就知道了,同时也试试下面这个:
sprintf(s,"%.2f",(double)i);
第一个打出来的肯定不是正确结果,原因跟前面提到的一样,参数压栈时调用者并不知道跟i
相对应的格式控制符是个%f而函数执行时函数本身则并不知道当年被压入栈里的是个整数,
于是可怜的保存整数i的那4个字节就被不由分说地强行作为浮点数格式来解释了,整个乱套了不过,如果有人有兴趣使用手工编码一个浮点数,那么倒可以使用这种方法来检验一下你手
工编排的结果是否正确?
字符/Ascii码对照
我们知道,在C/C++语言中,char也是一种普通的scalable类型,除了字长之外,它与short,int,long这些类型没有本质区别,只不过被大家习惯用来表示字符和字符串而已(或许当年该把这个类型叫做byte,然后现在就可以根据实际情况,使用byte或short来把char通过typedef定义出来,这样更合适些)
于是,使用%d或者%x打印一个字符,便能得出它的10进制或16进制的ASCII码;反过
来,使用%c打印一个整数,便可以看到它所对应的ASCII字符以下程序段把所有可见字符的ASCII码对照表打印到屏幕上(这里采用printf,注意#与%X合用时自动为16进制数增加0X前缀):
for(inti=32;i<127;i++){
printf("[%c]:
%3d0x%#04X\n",i,i,i);
}
连接字符串
sprintf的格式控制串中既然可以插入各种东西,并最终把它们连成一串,自然也就能够连
接字符串,从而在许多场合可以替代strcat,但sprintf能够一次连接多个字符串(自然也可以同时在它们中间插入别的内容,总之非常灵活)比如:
char*who="I";
char*whom="CSDN";
sprintf(s,"%slove%s.",who,whom);//产生:
"IloveCSDN."
strcat只能连接字符串(一段以\0结尾的字符数组或叫做字符缓冲,null-terminated-string),
但有时我们有两段字符缓冲区,他们并不是以\0结尾比如许多从第三方库函数中返回的字符数组,从硬件或者网络传输中读进来的字符流,它们未必每一段字符序列后面都有个相应的\0来结尾如果直接连接,不管是sprintf还是strcat肯定会导致非法内存操作,而strncat也至少要求第一个参数是个null-terminated-string,那该怎么办呢?
我们自然会想起前面介绍打印整数和浮点数时可以指定宽度,字符串也一样的比如:
chara1[]={'A','B','C','D','E','F','G'};
chara2[]={'H','I','J','K','L','M','N'};
如果:
sprintf(s,"%s%s",a1,a2);//Don'tdothat!
十有八九要出问题了是否可以改成:
sprintf(s,"%7s%7s",a1,a2);
也没好到哪儿去,正确的应该是:
sprintf(s,"%.7s%.7s",a1,a2);//产生:
"ABCDEFGHIJKLMN"
这可以类比打印浮点数的%m.nf,在%m.ns中,m表示占用宽度(字符串长度不足时补空
格,超出了则按照实际宽度打印),n才表示从相应的字符串中最多取用的字符数通常在打印字符串时m没什么大用,还是点号后面的n用的多自然,也可以前后都只取部分字符:
sprintf(s,"%.6s%.5s",a1,a2);//产生:
"ABCDEFHIJKL"
在许多时候,我们或许还希望这些格式控制符中用以指定长度信息的数字是动态的,而不是
静态指定的,因为许多时候,程序要到运行时才会清楚到底需要取字符数组中的几个字符,这种动态的宽度/精度设置功能在sprintf的实现中也被考虑到了,sprintf采用*来占用一个本来需要一个指定宽度或精度的常数数字的位置,同样,而实际的宽度或精度就可以和其它被打印的变量一样被提供出来,于是,上面的例子可以变成:
sprintf(s,"%.*s%.*s",7,a1,7,a2);
或者:
sprintf(s,"%.*s%.*s",sizeof(a1),a1,sizeof(a2),a2);
实际上,前面介绍的打印字符整数浮点数等都可以动态指定那些常量值,比如:
sprintf(s,"%-*d",4,'A');//产生"65"
sprintf(s,"%#0*X",8,128);//产生"0X000080","#"产生0X
sprintf(s,"%*.*f",10,2,3.1415926);//产生"3.14"
打印地址信息
有时调试程序时,我们可能想查看某些变量或者成员的地址,由于地址或者指针也不过是个32位的数,你完全可以使用打印无符号整数的%u把他们打印出来:
sprintf(s,"%u",&i);
不过通常人们还是喜欢使用16进制而不是10进制来显示一个地址:
sprintf(s,"%08X",&i);
然而,这些都是间接的方法,对于地址打印,sprintf提供了专门的%p:
sprintf(s,"%p",&i);
我觉得它实际上就相当于:
sprintf(s,"%0*x",2*sizeof(void*),&i);
利用sprintf的返回值
较少有人注意printf/sprintf函数的返回值,但有时它却是有用的,spritnf返回了本次函数调用
最终打印到字符缓冲区中的字符数目也就是说每当一次sprinf调用结束以后,你无须再调用一次strlen便已经知道了结果字符串的长度如:
intlen=sprintf(s,"%d",i);
对于正整数来说,len便等于整数i的10进制位数
下面的是个完整的例子,产生10个[0,100)之间的随机数,并将他们打印到一个字符数组s中,以逗号分隔开
#include
#include
#include
intmain(){
srand(time(0));
chars[64];
intoffset=0;
for(int