【1】.关于sprintf和snprintf的正确使用
考虑以下有缺陷的例子:
void f(const char *p)
{
char buf[11]={0};
sprintf(buf,"%10s",p); // very dangerous
printf("%sn",buf);
}
不要让格式标记“%10s”误导你。如果p的长度大于10个字符,那么sprintf() 的写操作就会越过buf的边界,从而产生一个缓冲区溢出。
检测这类缺陷并不容易,因为它们只在 p 的长度大于10个字符的时候才会发生。黑客通常利用这类脆弱的代码来入侵看上去安全的系统。
要修正这一缺陷,可以使用函数snprintf()代替函数sprintf()。
函数原型:int snprintf(char *dest, size_t n, const char *fmt, ...);
函数说明: 最多从源串中拷贝n-1个字符到目标串中,然后再在后面加一个0。所以如果目标串的大小为n的话,将不会溢出。
函数返回值: 若成功则返回存入数组的字符数,若编码出错则返回负值。
推荐的用法:
void f(const char *p)
{
char buf[11]={0};
snprintf(buf, sizeof(buf), "%10s", p); // 注意:这里第2个参数应当用sizeof(str),而不要使用硬编码11,也不应当使用sizeof(str)-1或10
printf("%sn",buf);
}
【转载】http://kapok.blog.51cto.com/517862/113471
【2】.返回值、缓冲区问题
snprintf函数的返回值
sprintf函数返回的是实际输出到字符串缓冲中的字符个数,包括null结束符。而snprintf函数返回的是应该输出到字符串缓冲的字符个数,所以snprintf的返回值可能大于给定的可用缓冲大小以及最终得到的字符串长度。看代码最清楚不过了:
char tlist_3[10] = {0};
int len_3 = 0;
len_3 = snprintf(tlist_3,10,"this is a overflow test!
");
printf("len_3 = %d,tlist_3 = %s
",len_3,tlist_3);
上述代码段的输出结果如下:
//////////////////////////////////////////////
// 输出的数据:"25", "this is a".
len_3 = 25, tlist_3 = this is a
所以在使用snprintf函数的返回值时,需要小心慎重,避免人为造成的缓冲区溢出,不然得不偿失。
snprintf函数的字符串缓冲
int sprintf(char *str, const char *format, ...);
int snprintf(char *str, size_t size, const char *format, ...);
上面的函数原型大家都非常熟悉,我一直以为snprintf除了多一个缓冲区大小参数外,表现行为都和sprintf一致,直到今天遇上的bug。在此之前我把下面的代码段的两个输出视为一致。
char tlist_1[1024] = {0},tlist_2[1024]={0};
char fname[7][8] = {"a1","b1","c1","d1","e1","f1","g1"};
int i = 0, len_1,len_2 = 0;
len_1 = snprintf(tlist_1,1024,"%s;",fname[0]);
len_2 = snprintf(tlist_2,1024,"%s;",fname[0]);
for(i=1;i<7;i++)
{
len_1 = snprintf(tlist_1,1024,"%s%s;",tlist_1,fname[i]);
len_2 = sprintf(tlist_2,"%s%s;",tlist_2,fname[i]);
}
printf("tlist_1: %s
",tlist_1);
printf("tlist_2: %s
",tlist_2);
可实际上得到的输出结果却是:
////////////////////////////////////////////
// snprintf()会清除缓冲区,sprintf()不会清除缓冲区;
tlist_1: g1;
tlist_2: a1;b1;c1;d1;e1;f1;g1;
【转载】http://my.oschina.net/shelllife/blog/177279
【3】.三个打印函数printf()/sprintf()/snprintf()区别
先贴上其函数原型
printf( const char *format, ...) 格式化输出字符串,默认输出到终端-----stdout
sprintf(char *dest, const char *format,...) 格式化输出字符串到指定的缓冲区
snprintf(char *dest, size_t size,const char *format,...) 按指定的SIZE格式化输出字符串到指定的缓冲区
printf()函数在这就不再讨论,这里主要讨论sprintf()与snprintf()的用法及区别,
#include "stdafx.h"
#include <stdio.h>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
char *p1="China";
char a[20];
sprintf(a,"%s",p1);
printf("%s
",a);
//////////////////////////
memset(a,0,sizeof(a));
_snprintf(a,3,"%s",p1);
printf("%s
",a);
printf("%d
",strlen(a));
return 0;
}
结果输出:
China
Chi
3
分析:
sprintf(a,"%s",p1) 把p1字符串拷贝到数组a中(' '也拷贝过去了)。
snprintf(a,3,"%s",p1) 拷贝P1中前3个字符到数组a中,并在末尾自动添加' '。
sprintf属于I/O库函数,snprintf函数并不是标准c/c++中规定的函数,但是在许多编译器中,厂商提供了其实现的版本。在gcc中,该函数名称就snprintf,而在VC中称为_snprintf。 如果你在VC中使用snprintf(),会提示此函数未声明,改成_snprintf()即可。
注意点:
1 sprintf是一个不安全函数,src串的长度应该小于dest缓冲区的大小,(如果src串的长度大于或等于dest缓冲区的大小,将会出现内存溢出。)
2 snprintf中源串长度应该小于目标dest缓冲区的大小,且size等于目标dest缓冲区的大小。(如果源串长度大于或等于目标dest缓冲区的大小,且size等于目标dest缓冲区的大小,则只会拷贝目标dest缓冲区的大小减1个字符,后加' ';该情况下,如果size大于目标dest缓冲区的大小则溢出。)
3 snprintf ()函数返回值问题, 如果输出因为size的限制而被截断,返回值将是“如果有足够空间存储,所应能输出的字符数(不包括字符串结尾的' ')”,这个值和size相等或者比size大!也就是说,如果可以写入的字符串是"0123456789ABCDEF"共16位,但是size限制了是10,这样 snprintf() 的返回值将会是16 而不是10!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
【转载】http://www.cnblogs.com/ningskyer/articles/4037964.html
【4】. <string.h> 、<string>
<string.h> 是C语言的一个【头文件】,里
面有 定义了 很多操作字符串的【方法】,例如:
strcpy(), strncpy(),
strcat(), stncat(),
strcmp(), strncmp(),
// 找子串
strstr()
strlen()
memset()
<string> 里面定义了一个 string 类,其功能和一容器类似。
string类的方法有:
at(), append(), assign(), begin(), end(),
earse(), find(), insert(),
clear(), length(), c_str(),
// Returns whether the string is empty
empty(),
push_back(),
size(),
string 类定义的对象,可以直接加上字符串。
要访问string类对象中保存的字符串,需要调用类的c_str()方法。
----------------------------------------------------------------------------
-----------------------------------------------------
strlen,sizeof()
char mystr[100]="test string";
defines an array of characters with a size of 100 chars, but the C string with which mystr has ben initialized has a length of only 11 characters.
Therefore, while sizeof(mystr) evaluates to 100,
strlen(mystr) returns 11.
【5】.C里操作字符串很高效,但也很麻烦。
1. char * strcpy ( char * destination, const char * source );
最常用的函数,但是却不安全,原因在于,一是要destination有足够的空间,二是要保证source和destination指向的空间没有overlap。
2. int sprintf ( char * str, const char * format, ... );
也许要问,这个怎么用于字符串拷贝呢?可以这么用 sprintf(dest, "%s", src); 但是要调用者保证dest有足够的内存存放src。
3. char * strncpy ( char * destination, const char * source, size_t num );
比起strcpy,多了个长度的控制。从source拷贝num个字符到destination。如果source里不够num字符怎么办呢?会补充0。
一个典型的用法是:
char buf[MAX];
strncpy(buf, src, MAX-1);
这段代码的本意是,一个长为MAX的buf,最多也就放MAX-1个字符,最后一个位置放‘