sprintf函数用法详解,sprintf与sprintf_s

  sprintf函数用法详解,sprintf与sprintf_s

  sprintf(s, %-10.3f ,3.1415626);//生成:“3.142”

  sprintf(s, %.3f ,3.1415626);//未指定总宽度,结果为:“3.142”

  注意一个问题,你猜int i=100

  sprintf(s, %.2f ,I);

  会打什么?"100.00"?正确自己试试,也试试下面的:sprintf(s, %.2f ,(double)I);

  第一种肯定不是正确的结果。原因和前面说的一样。参数堆叠时,调用者不知道I对应的格式控制器是一个“%f”。函数在执行的时候,函数本身并不知道当年推入堆栈的整数是整数,所以保存整数I的可怜的四个字节被强行解释为浮点数格式,弄得整个一塌糊涂。

  但是,如果有人对手工编码浮点数感兴趣,你可以用这个方法来检查你手工排列的结果是否正确。J

  字符/Ascii代码比较

  我们知道,在C/C语言中,char也是一种普通的可伸缩类型。除了字长,它和short、int、long没有本质区别,只是用来表示字符和字符串。(也许当年应该把这种类型叫做“byte”,现在可以根据实际情况用byte或者short通过typedef定义char,这样更合适)

  然后,通过打印一个带有“%d”或“%x”的字符,可以得到它的十进制或十六进制ASCII码;反过来用“%c”打印一个整数,可以看到其对应的ASCII字符。下面的程序段打印屏幕上所有可见字符的ASCII码对照表(这里用的是printf。注意,当“#”和“%X”一起使用时,前缀“0X”会自动添加到十六进制数中):for(int I=32;i 127i ) {

  printf([ %c ]:=0x%#04X\n ,I,I,I);

  }

  3.连接字符串

  既然各种东西都可以插入到sprintf的格式控制字符串中,最后可以“连成一串”,那么连接字符串自然是可以的,从而在很多场合取代strcat。但是sprintf可以一次连接多个字符串(自然也可以同时插入其他内容,总之非常灵活)。比如:char * who= I

  char * whom= CSDN ;

  sprintf(s, %s爱%s . ,谁,谁);//生成:‘我爱CSDN。’

  Strcat只能连接字符串(以 \0 结尾的字符数组或称为字符缓冲区,null-terminated-string),但有时我们有两个字符缓冲区,它们不以 \0 结尾。例如,从第三方库函数返回的许多字符数组和从硬件或网络传输中读取的字符流可能并不总是在每个字符序列的末尾有相应的“\0”。如果直接连接,不管是sprintf还是strcat,肯定会导致内存非法操作,strcat也要求至少第一个参数是空终止的-string,怎么办?很自然的,我们会记住在打印整数和浮点数的时候可以指定宽度,字符串也是一样。示例:char a1 []={a , b , c , d , e , f , g };

  char a2[]={H , I , J , K , L , M , N };

  If: sprintf(s, %s%s ,a1,a2);//不要这样!

  十有八九会出问题。可以改成: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”

  4.打印地址信息

  有时候,在调试程序时,我们可能想要检查一些变量或成员的地址。由于地址或指针只是32位的数字,您可以使用“%u”打印它们,它打印无符号整数:sprintf(s, %u ,

  然而,人们通常更喜欢用十六进制而不是十进制来显示地址:sprintf(s,X x ,

  然而,这些都是间接的方法。对于地址打印,sprintf提供了一个特殊的“%p”:Sprintf(s, % p ,

  我认为它实际上相当于:

  sprintf(s, %0*x ,2 * sizeof(void *),

  5.使用sprintf的返回值

  很少有人关注printf/sprintf函数的返回值,但有时候很有用。spritnf在这个函数调用中返回打印到字符缓冲区中的字符数。也就是说,每次sprinf调用结束,不需要再次调用strlen就可以知道结果字符串的长度。例如int len=sprintf(s, %d ,I);

  对于正整数,len等于整数I的小数位数。

  下面是一个完整的例子,在[0,100]之间生成10个随机数,打印到字符数组S中,用逗号分隔。#包含stdio.h

  #包含时间. h

  #包含stdlib.h

  int main() {

  srand(time(0));

  char s[64];

  int offset=0;

  for(int I=0;i i ) {

  offset=sprintf(s offset, %d ,rand()% 100);

  }

  s[offset-1]= \ n ;//用换行符替换最后一个逗号。

  printf

  返回0;

  }

  想象一下,当你从数据库中取出一条记录,然后你想按照一些规则把它们的字段连接成一个字符串,你就可以使用这个方法。理论上应该比常量strcat更高效,因为strcat每次调用都需要先找到最后一个 \0 位置,而在上面给出的例子中,我们每次都是用sprintf返回值直接记下这个位置。

  6.关于使用sprintf的常见问题

  Sprintf是一个可变参数函数,使用时经常出错,而且只要出错,通常都是内存访问错误,可以导致程序崩溃。幸运的是,虽然误用sprintf导致的问题很严重,但是很容易发现。只有少数情况,一般用眼睛看错别字就能看出来。

  ?缓冲区溢出

  第一个参数长度太短,没什么好说的。给它一个更大的地方。当然也可能是下面参数的问题。建议您在更改参数时要小心。打印字符串时,尽量使用“%”的形式。ns”来指定最大字符数。

  ?忘记了第一个参数

  不可能是低级问题。我太习惯用printf了。//我经常做。(

  ?改变参数有问题。

  通常忘记提供某个格式字符对应的变量参数,导致以后的参数都放错了位置。检查一下。尤其是“*”对应的那些参数,都有提供吗?不要把一个整数对应一个" %s ",编译器会认为你太欺负她了(编译器是obj和exe的母亲,应该是女的,P)。

  7.得到指定格式的时间

  Sprintf还有一个很好的表亲:strftime,专门用于格式化时间字符串。它的用法和她表姐很像,也是很多格式控制器。只是毕竟小姑娘谨慎,还得让打电话的人指定缓冲区的最大长度,大概是为了出了事可以推卸责任。下面举个例子:time _ t t=time(0);

  //生成格式为“YYYY-MM-DD hh:mm:ss”的字符串。

  char s[32];

  strftime(s,sizeof(s), %Y-%m-%d %H:%M:%S ,localtime( t))。

  Sprintf也能在MFC: CString:Format中找到知音,strftime自然也有她在MFC: CTime:Format中的同道好友。这对赞助面向对象,用来写的代码更优雅。

  8.附言

  本文中介绍的所有这些功能在MSDN都很容易找到。笔者只是根据自己的经验和一些例子介绍一些可能很多初学者不知道的常用有用的用法。希望大家不要嘲笑他们,批评他们。

  有人认为这种参数可变的函数会产生各种问题,不建议使用。但是作者本人也抵挡不住它们强大功能的诱惑,一直在实际工作中使用。其实是C#。NET从一开始就支持可变参数,刚刚发布的Java5.0也支持可变参数。

  感谢ericzhangali(另一个空间)仔细审阅了整篇稿件,改正了许多小错误,并提出了一些建议。也感谢老麦看完整稿,并给出了一些增删部分内容的建议。

  获取系统时间:void获取系统时间(LP系统时间LP系统时间);下面是一个例子:

  #包含windows.h

  #包含stdio.h

  #包含stdlib.h

  void main() {

  SYSTEMTIME st//定义存储时间的结构

  char strTime[256];

  int n=“0”;

  getsystem time(ST);

  n=sprintf(strTime, Year:\t%d\n ,ST . wyear);

  n=sprintf(strTime n, Month:\t%d\n ,ST . wmonth);

  n=sprintf(strTime n, Day:\t%d\n ,ST . wday);

  n=sprintf(strTime n, Date:\t%d\n ,ST . wdayofweek);

  n=sprintf(strTime n, Hour:\t%d\n ,ST . whour);

  n=sprintf(strTime n, Minute:\t%d\n ,ST . wminute);

  n=sprintf(strTime n, Second:\t%d\n ,ST . w Second);

  n=sprintf(strTime n,毫秒:\t%d\n ,ST . wmillseconds);

  printf(%s ,strTime);

  系统(“暂停”);

  }

  ******************************************

  表格是需要输出的一系列参数,其编号必须与格式化字符串描述的输出相同。

  参数个数相同,参数之间用,分隔,顺序一一对应,否则会有一个期望。

  没有错。

  1.格式指定符

  Turbo C2.0提供了以下格式规范:

  符号功能

  %d个十进制有符号整数

  %u十进制无符号整数

  %f浮点数

  %s字符串

  %c单个字符

  %p指针的值

  %e指数形式的浮点数

  %x,%X十六进制无符号整数

  八进制的%0无符号整数

  %g自动选择适当的表示。

  描述:

  (1).可以在“%”和字母之间插入数字来表示最大字段宽度。

  比如:=表示输出3位整数,不够3位右对齐。

  %9.2f表示输出字段宽度为9的浮点数,其中小数位为2,整数位为6。

  一个小数点,不够九右对齐。

  %8s表示输出8个字符的字符串,这对于右对齐是不够的。

  如果字符串的长度或整数位数超过规定的字段宽度,将按其实际长度输出。

  但对于浮点数,如果整数位超过了规定的整数位宽,则按照实际整数位输出;

  如果小数位数超过描述中小数位数的宽度,将根据描述的宽度进行四舍五入输出。

  另外,如果要在输出值前加一些零,应该在字段宽度项前加一个零。

  比如D表示输出小于4位数的值时,会用0填充,使其总宽度。

  是4位。

  如果用浮点数表示字符或整数的输出格式,小数点后的数字表示最大宽度,

  小数点前的数字代表最小宽度。

  例如:%6.9s表示显示长度不小于6且不大于9的字符串。如果它大于9,则

  第9个字符后的内容将被删除。

  (2).您可以在“%”和字母之间添加小写字母L,表示输出是一个长数字。

  例如:%ld表示输出长整数。

  %lf表示输出双浮点数。

  (3).您可以控制输出的左对齐或右对齐,即在“%”和字母can之间添加一个“-”号

  输出左对齐;否则,它是右对齐的。

  例如,%-7d表示输出的7位整数左对齐。

  %-10s表示10个字符的输出左对齐。

  2.一些特殊的指定字符

  字符函数

  \n换行

  \f清除屏幕并换页。

  \r输入

  \ t制表符

  \xhh表示ASCII代码以十六进制表示,

  其中hh是1到2个十六进制数。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: