您的位置:首页 > 其它

sprintf函数你了解有多深!

2008-11-10 10:46 288 查看
1、在使用每一个函数时都要注意任何一个微小的细节。同一个函数的使用,高手可以控制的很好。我是菜鸟,所以范了下面的错误。
int sprintf(char *, const char *, ...),
int sscanf(const char *, const char *, ...)
注意了么,里面的参数是char*型的,也就是字符串。
看下面的一段程序:
在VC6.0下,控制台程序,在属性页中使用MFC。
#include <stdio.h>
#include <afx.h>
typedef unsigned char byte;
void main()
{
byte len[4]={0};
byte length[8]={0};
sprintf((char *)len,"%04X",4); //1
sprintf((char *)length,"B%cB%cB%cB%c",len[3],len[2],len[1],len[0]);//2
sscanf((const char *)length,"%2x%2x%2x%2x",&len[0],&len[1],&len[2],&len[3]);//3
}

大家看这段程序是否有问题?
回答是肯定的,但它在你的机子上跑可能没问题,这要看地址是如何分配的。如果len和length的地址是紧挨着的,那就要出问题了。
在我的机器上运行时,会出现这个程序出现问题了,你是否发送报告这样的错误。
跟踪一下,可以看到len的地址是0x0012ff7c,length的地址是0x0012ff74。可以看出两者之间的字节正好是8个,而这8个字节是存放length中的元素的。
在程序中,我们好像控制的非常好,没有出现溢出的情况。但事实上是溢出了,我们可以在1、2、3处加上输出语句,注意绝对不能用printf("%s",len)的形式输出,以为我们没让len存放'\0'。程序如下:
#include <stdio.h>
#include <afx.h>
typedef unsigned char byte;
void main()
{
byte len[4]={0};
byte length[8]={0};
int i;

sprintf((char *)len,"%04X",4);
for(i=0; i<4; i++) //1
printf("%4c",len[i]);
printf("\n");

sprintf((char *)length,"B%cB%cB%cB%c",len[3],len[2],len[1],len[0]);
for(i=0; i<4; i++) //2
printf("%4c",len[i]);
printf("\n");

sscanf((const char *)length,"%2x%2x%2x%2x",&len[0],&len[1],&len[2],&len[3]);
for(i=0; i<8; i++) //3
printf("%4c",length[i]);
printf("\n");
}
结果中1,3处都是正确的,而2处结果是不对了。结果如下图



为什么呢?该到关键处了。
在第一个sprintf执行前时,74-7f中的值都为0,*代表未知。在第一个sprintf执行完后,在内存中的形式是

length len
0x0012ff74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81
0 0 0 4 NULL *
注意到80位置处变为0了么。这是关键啊!sprintf执行时,后面自动把后面的一个字节变为NULL。
在执行完第二条语句后,内存形式为

length len
0x0012ff74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81
B 4 B 0 B 0 B 0 NULL 0 0 4 0 *
注意到len的起始地址变为NULL了么,这是程序出错的根本。

若是len和length的地址不紧挨着就没事了(就本程序来说,不是绝对的)。我们可以刻意不让他们的地址挨着。程序如下:
#include <stdio.h>
#include <afx.h>
typedef unsigned char byte;
void main()
{
byte A[10];
byte len[4]="";
byte B[10];
byte length[8]={0};
byte C[10];
sprintf((char *)len,"%04X",4);
sprintf((char *)length,"B%cB%cB%cB%c",len[3],len[2],len[1],len[0]);
sscanf((const char *)length,"%2x%2x%2x%2x",&len[0],&len[1],&len[2],&len[3]);

}
运行就不会有问题了,但这没有解决问题的关键。

总结:
在上面的问题中,sprintf中的第一个参数是char*的形式。将后面的变量变为字符串时,后面需要加NULL的。在这由于是 sprintf((char*)len,"%04",4),%04使0004占满了len中的所有空间,所以将len空间后的内存变为了NULL。而变为 NULL的这个字节正好是导致错误出现的区域,因为它不在我们的控制范围之内。
要解决,就是把len和length多分配一个空间,使他们在我们的控制之下就安全了。

最后说一下,单纯看这个程序,大家可能很快找到错误发生在哪。但是对于一个工程,要是出现这样的错误,恐怕你得调一阵了。所以还请大家多多积累,掌握每个细节。高手就是能抓住每个细节,看似都会的东西,就看你能理解到多深,多透了。

说的不对的地方,请大家多多指教。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: