认识sprintf函数及snprintf

认识sprintf函数

2014/6/21 14:17:24

初识sprintf函数


sprintf函数的原型如下

int sprintf( char *buffer, const char *format [, argument] ... );

sprintf函数的格式存储了一系列缓冲区中的字符和值。每个参数是根据相应的格式规范的格式转换和输出。该格式由普通字符并具有相同的形式和功能作为格式参数的printf的。自动在字符串的末尾追加空字符'\0'。如果重叠的字符串之间发生拷贝,其行为是未定义的。

buffer为要写入的字符串,format为格式化字符串,argument是要保存的数据。除了前两个参数类型固定外,后面可以接任意多个参数。而它的精华,显然就在第二个参数--格式化字符串--上。 printf()和sprintf()都使用格式化字符串来指定串的格式,在格式串内部使用一些以“%”开头的格式说明符(format specifications)来占据一个位置,在后边的变参列表中提供相应的变量,最终函数就会用相应位置的变量来替代那个说明符,产生一个调用者想要的字符串

自动在字符串的末尾追加空字符'\0'。

#include<stdio.h>
#include<string.h>
int main()
{
   char str[20] ={0};
   sprintf(str,"%d",'a');
   printf("%d",str);
   prinrf("%d\n",strlen(str));
   return 0;
 }

sprintf()最常见的应用之一莫过于把整数打印到字符串中,如:

sprintf(s, "%d", 123);     //把整数123打印成一个字符串保存在s中
sprintf(s, "%8x", 4567);   //小写16进制,宽度占8个位置,右对其
sprintf(s, "%-10X“,123);   //大写16进制,占宽度为10,左对齐
sprintf(s, "%010x",123);   //小写16进制,占1宽度为10,右对齐,左边空位补0.
sprintf(s, "%010o",123);    //把123转换为8进制数,将该8进制数以在字符串形式保存在数组中,占10位,右对齐,不足处补0.

sprintf函数也可以连接字符串

利用sprintf函数可以存储字符串的功能,如果我们连续存数多个字符串(不重叠),是不是就达到了连接字符创的功能呢!

#include<stdio.h>
int main()
{
char *targe1="Do you like";
char  *targe2="Programer?";
char str[50] ={0};
sprintf(str,"%s %s",targe1,targe2);
printf("%s\n",str);
return 0;
}

运行一下,果然是这样的!

下面这中方法也是可以的。(MSDN例子)

#include <stdio.h>

int main( void )
{
char buffer[200], s[] = "computer", c = 'l';
int i = 35, j;
float fp = 1.7320534f;

/* Format and print various data: */
j = sprintf( buffer, "\tString:%s\n", s );
j += sprintf( buffer + j, "\tCharacter: %c\n", c );
j += sprintf( buffer + j, "\tInteger: %d\n", i );
j += sprintf( buffer + j, "\tReal: %f\n", fp );

printf( "Output:\n%s\ncharacter count = %d\n", buffer, j );
return 0;
}
//第一看到这代码还是觉得蛮巧妙的,利用了sprintf函数返回值(本次成功写入buffer中字符的数目)

字符数组怎么办 ?

有时候,我们没有在字符串,只有字符数组。要知道,字符串的结尾有'\0'这个空字符作为标志,而数组没有。那么我怎才能使用sprintf函数来连接连个字符数组呢?

char str1[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'}; char str2[] = {'H', 'I', 'J', 'K', 'L', 'M', 'N'};

直接连接肯定是不行了的,因为在存储第一个数组的时候,并不知道结尾在那里,所以我们应该想存储整数和浮点数一样,给定一个宽度,最多读取长度是多少。

char str[100]={0};
sprintf(str,"%.7s%.7s",str1,str2);//str1的长度是7,str2的长度也是7。

这可以类比打印浮点数的”%m/nf”,在”%m.ns”中,m 表示占用宽度(字符串长度不足时补空格,超出了则按照实际宽度打印),n 才表示从相应的字符串中最多取用的字符数。通常在打印字符串时m 没什么大用,还是点号后面的n 用的多。自然,也可以前后都只取部分字符:

sprintf(s, "%.6s%.5s", str1, str2);//产生:"ABCDEFHIJKL"

在许多时候,我们或许还希望这些格式控制符中用以指定长度信息的数字是动态的,而不是静态指定的,因为许多时候,程序要到运行时才会清楚到底需要取字符数组中的几个字符,这种动态的宽度/精度设置功能在sprintf 的实现中也被考虑到了,sprintf 采用”*”来占用一个本来需要一个指定宽度或精度的常数数字的位置,同样,而实际的宽度或精度就可以和其它被打印的变量一样被提供出来,于是,上面的例子可以变成:

sprintf(s, "%.s%.s", 7, str1, 7, str2);

或者:

sprintf(s, "%.s%.s", sizeof(str1), str1, sizeof(str2), str2);

实例1:

#include<stdio.h>
int main()
{
char str[60]={0};
sprintf(str,"&-*d",5,'2');将字符2以整数保存,占宽度为5
printf("%s",str);
sprintf(str,"%#0*X",8,128);//产生"0X000080","#"产生0X
printf("%s",str);
sprintf(str,"%*.*f",10,2,3.1415926);//占10位,保留2为小数,右对齐
printf("%s",str);
return 0;
}

实例2:

#include<stdio.h>
#include<string.h>
int main()
{
char str1[]={'a','d','d,'s','d','d','d','g','d','g','h','k','r'};
char str2[]={'1','5','8','9','0','k','4'};
char str[100}={0];
sprintf(str,"%.*s%.*s",str1,str2);
printf("%s\n",str);
return 0;
}

sprintf函数的缺点

sprintf函数在使用中很容易发生缓冲区溢出,因为没有限定写入buffer的数据的长度,所以当buffer的长度不够时发生溢出,从而破坏程序的堆栈,不法分子用这一缺陷来干一些坏事。所以我们用sprintf的Secure version(snprintf)来代替它。

snprintf函数

snprintf函数的原型: int snprintf(char *str, size_t size, const char *format, ...);

size限定了写入buffer的长度。一般的size ==sizeof(bffer).如果格式话后字符创的长度小于size,则可以将字符串完全写入buffer,否则字符串会被截断,只将前面 size -1字符保存在buffer中,最后一个字节自动补充 '\0'。

posted @ 2014-06-21 14:50  水墨沙场  阅读(864)  评论(0编辑  收藏  举报