char ch[2];
sprintf(ch, "%x", 100);
printf("字符串%%s输出:%s\n", ch);
printf("字符%%c输出ch:%c\n", ch);
printf("字符%%c输出ch[0]:%c\n", ch[0]);
printf("字符%%c输出ch[1]:%c\n", ch[1]);
printf("十六进制%%x输出ch:%x\n", ch);
printf("十六进制%%x输出ch[0]:%x\n", ch[0]);
printf("十六进制%%x输出ch[1]:%x\n", ch[1]);
printf("十进制%%d输出ch:%d\n", ch);
printf("十进制%%d输出ch[0]:%d\n", ch[0]);
printf("十进制%%d输出ch[1]:%d\n", ch[1]);
输出:
字符串%s输出:64
字符%c输出ch:>
字符%c输出ch[0]:6
字符%c输出ch[1]:4
十六进制%x输出ch:22ff3e
十六进制%x输出ch[0]:36
十六进制%x输出ch[1]:34
十进制%d输出ch:2293566
十进制%d输出ch[0]:54
十进制%d输出ch[1]:52
说明:
int sprintf( char *buffer, const char *format, [ argument] … );
sprintf指的是字符串格式化命令,主要功能是把格式化的数据写入某个字符串中。
100十六进制为64,ch中存入'6''4',以%c字符输出时ch[0]='6',ch[1]='4'
以%d十进制数输出时,对应这两个字符的ACSII码为 54 52
同理,%x十六进制输出时,对应54 52的十六进制36 34
printf("字符%%c输出ch:%c\n", ch);
printf("十六进制%%x输出ch:%x\n", ch);
printf("十进制%%d输出ch:%d\n", ch);
这两个输出的结果是不好理解的,刚开始以为是由高位54低位52组成的一个十六位数,测试了多次结果都不对,后来在VS里面测试发现这个结果每次都是变化的,才想到这是指针,也就是ch的地址。
char[]是“特殊的”数组,是由char组成的字符串,数组名代表地址,也是指向存放该数组的地址的指针。对于数组名,当以%s输出时,就将各个字符以整体字符串的形式输出,以数字的形式(包括%c %d %x)时,输出地址,而%c是1个字节,地址是4个字节,所以地址被截取为1个字节后输出,将4个字节的int类型截取为1个字节char类型,测试后%d会输出63,对应ASCII为'?'
PS:发现Linux和Windows的编译器区别,GCC中同一程序多次运行时变量地址保持不变,而在VS中每次都会变化。
sprintf 是个变参函数。
可变参数函数顾名思义,就是函数参数个数是未知的是可变的。sprintf中[ argument]的参数和format中的格式化符号一一对应。
sprintf 对于写入buffer的字符数是没有限制的,这就存在了buffer溢出的可能性。
例如:
char buffer[2];
sprintf(buffer, "%x", 1000);
printf("格式化后buffer:%s\n长度:%d\n", buffer, strlen(buffer));
输出:
格式化后buffer:3e8
长度:3
说明:
首先定义一个长度为2的char数组buffer,然后使用sprintf将1000以十六进制存入buffer,1000十六进制为3e8,所有buffer长度变为3,发生溢出。
4字节“暴力”截取1字节
union A
{
int i;
char c;
};
union A a;
a.i=2293567;
printf("截取后:十进制%d,字符%c\n", a.c, a.c);
输出:
截取后:十进制63,字符?