“Sprintf“和“Printf“两兄弟的前世今生

前几天调试SD卡的过程中看到Sprintf函数,发现在建立文件的时候都会用到这个函数,查询之后发现他和printf函数还有有点区别,把自己的一些理解都分享给大家。

Sprintf函数的用法

sprintf()函数用于将格式化的数据写入字符串,其原型为:
int sprintf(char *str, char * format [, argument, …]);

1、该函数包含在stdio.h的头文件中。

2、sprintf和平时我们常用的printf函数的功能很相似sprintf函数打印到字符串中(要注意字符串的长度要足够容纳打印的内容,否则会出现内存溢出),而printf函数打印输出到屏幕上sprintf函数在我们完成其他数据类型转换成字符串类型的操作中应用广泛。

3、sprintf函数的格式:
int sprintf( char buffer, const char format [, argument,…] );
除了前两个参数固定外,可选参数可以是任意个
。buffer是字符数组名**;format是格式化字符串(像:”%3d%6.2f%#x%o”,%与#合用时,自动在十六进制数前面加上0x)。只要在printf中可以使用的格式化字符串,在sprintf都可以使用。其中的格式化字符串是此函数的精华。
printf 和sprintf都使用格式化字符串来指定串的格式,在格式串内部使用一些以”%”开头的格式说明符来占据一个位置,在后边的变参列表中提供相应的变量,最终函数就会用相应位置的变量来替代那个说明符,产生一个调用者想要的字符串。

4、可以控制精度
char str[20];
double f=14.309948;
sprintf(str,”%6.2f”,f);

5、可以将多个数值数据连接起来
char str[20];
int a=20984,b=48090;
sprintf(str,”%3d%6d”,a,b);
str[]=”20984 48090”

6、可以将多个字符串连接成字符串
char str[20];
char s1[5]={‘A’,’B’,’C’};
char s2[5]={‘T’,’Y’,’x’};
sprintf(str,”%.3s%.3s”,s1,s2);
%m.n在字符串的输出中,m表示宽度,字符串共占的列数;n表示实际的字符数。%m.n在浮点数中,m也表示宽度;n表示小数的位数。

7、可以动态指定,需要截取的字符数
char str[20];
char s1[5]={‘A’,’B’,’C’};
char s2[5]={‘T’,’Y’,’x’};
sprintf(str,”%.*s%.s”,2,s1,3,s2);
sprintf(str, “%
.*f”, 10, 2, 3.1415926);

8、可以打印出i的地址
char str[20];
int i;
sprintf(str, “%p”, &i);
上面的语句相当于
sprintf(str, “%0*x”, 2 * sizeof(void *), &i);

9、sprintf的返回值是字符数组中字符的个数,即字符串的长度,不用在调用strlen(str)求字符串的长度。

10、使用字符指针指向的字符串来接收打印的内容

For example:

int main()
{
    
    
    int ddd=666;
    char *buffer=NULL;    
    if((buffer = (char *)malloc(80*sizeof(char)))==NULL)
    {
    
    
        printf("malloc error\n");
    }
    sprintf(buffer, "The value of ddd = %d", ddd);//The value of ddd = 666
    printf("%s\n",buffer);
    free(buffer);
    buffer=NULL;
    return 0;
}

指针刚开始定义的时候,并不指向所处,可以指向一个变量,然后可以用,如果要单纯用这个指针,那么要给这个指针malloc分配一片内存,加了malloc就要加stdlib.h

12、 格式化数字字符串

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

(1)把整数123打印成一个字符串保存在s中。

sprintf(s, “%d”, 123); //产生“123″
(2)可以指定宽度,不足的左边补空格:

sprintf(s, “%8d%8d”, 123, 4567); //产生:“ 123 4567″
当然也可以左对齐:
sprintf(s, “%-8d%8d”, 123, 4567); //产生:“123 4567″

(3)也可以按照16进制打印:
sprintf(s, “%8x”, 4567); //小写16进制,宽度占8个位置,右对齐
sprintf(s, “%-8X”, 4568); //大写16进制,宽度占8个位置,左对齐
这样,一个整数的16进制字符串就很容易得到,但我们在打印16进制内容时,通常想要一种左边补0的等宽格式,那该怎么做呢?很简单,在表示宽度的数字前面加个0就可以了。
sprintf(s, “%08X”, 4567); //产生:“000011D7″
上面以”%d”进行的10进制打印同样也可以使用这种左边补0的方式。
这里要注意一个符号扩展的问题:比如,假如我们想打印短整数

**(4)(short)-1的内存16进制表示形式,**在Win32平台上,一个 short型占2个字节,所以我们自然希望用4个16进制数字来打印它:
short si = -1;
sprintf(s, “%04X”, si);
产生“FFFFFFFF,怎么回事?因为 sprintf是个变参函数,除了前面两个参数之外,后面的参数都不是类型安全的,函数更没有办法仅仅通过一个“%X”就能得知当初函数调用前参数压栈时 被压进来的到底是个4字节的整数还是个2字节的短整数,所以采取了统一4字节的处理方式,导致参数压栈时做了符号扩展,扩展成了32位的整数-1,打印时 4个位置不够了,就把32位整数-1的8位16进制都打印出来了。如果你想看si的本来面目,那么就应该让编译器做0扩展而不是符号扩展(扩展时二进制左边补0而不是补符号位):
sprintf(s, “%04X”, (unsigned short)si);
就可以了。或者:
unsigned short si = -1;
sprintf(s, “%04X”, si);
sprintf和printf还可以按8进制打印整数字符串,使用”%o”。注意8进制和16进制都不会打印出负数,都是无符号的,实际上也就是变量的内部编码的直接用16进制或8进制表示。

printf函数的用法

输入输出函数(printf 和 scanf)是C语言中非常重要的两个函数,也是学习C语言必学的两个函数。在C语言程序中,几乎没有一个程序不需要这两个函数,尤其是输出函数(printf),所以这两个函数必须要掌握。

如果在程序中要使用 printf ,那么就必须要包含头文件 stdio.h。因为这个函数就是包含在该头文件中的。
**输出函数的功能是将程序运行的结果输出到屏幕上,而输入函数的功能是通过键盘给程序中的变量赋值。**可以说输入输出函数是用户和计算机交互的接口。其中 printf 的功能很强大,用法很灵活,比较难掌握。

printf 的格式

printf 函数的原型为:

# include <stdio.h>
int printf(const char *format, ...);

在讲每一个函数的时候都会先把它的函数原型写出来,这个原型你们现在看不懂不要紧,等到学完C语言之后再来看这个原型就会发现它是很有参考意义的!它对深刻理解函数有着很大的价值。

printf 的格式有四种:

1) printf(“字符串\n”);

# include <stdio.h>
int main(void)
{
    
    
    printf("Hello World!\n");  // \n表示换行
    return 0;
}

其中\n表示换行的意思。它是一个转义字符,前面在讲字符常量的时候见过。其中 n 是“new line”的缩写,即“新的一行”。
此外需要注意的是,printf 中的双引号和后面的分号必须是在英文输入法下。双引号内的字符串可以是英文,也可以是中文。

2) printf(“输出控制符”,输出参数);

# include <stdio.h>
int main(void)
{
    
    
    int i = 10;
    printf("%d\n", i);  /*%d是输出控制符,d 表示十进制,后面的 i 是输出参数*/
    return 0;
}

这句话的意思是将变量 i 以十进制输出。

那么现在有一个问题:i 本身就是十进制,为什么还要将 i 以十进制输出呢?

因为程序中虽然写的是 i=10,但是在内存中并不是将 10 这个十进制数存放进去,而是将 10 的二进制代码存放进去了。计算机只能执行二进制 0、1 代码,而 0、1 代码本身并没有什么实际的含义,它可以表示任何类型的数据。所以输出的时候要强调是以哪种进制形式输出。所以就必须要有“输出控制符”,以告诉操作系统应该怎样解读二进制数据。

如果是%x就是以十六进制的形式输出,要是%o就是以八进制的形式输出,大家自己试一下。

3) printf(“输出控制符1 输出控制符2…”, 输出参数1, 输出参数2, …);

# include <stdio.h>
int main(void)
{
    
    
    int i = 10;
    int j = 3;
    printf("%d %d\n", i, j);
    return 0;
}

输出控制符 1 对应的是输出参数 1,输出控制符 2 对应的是输出参数 2……编译、链接、执行后我们看一下输出结果:
10 3

注意一下,为什么 10 和 3 之间有一个空格?因为上面 %d 和 %d之间有空格,printf 中双引号内除了输出控制符和转义字符\n外,所有其余的普通字符全部都原样输出。比如:

# include <stdio.h>
int main(void)
{
    
    
    int i = 10;
    int j = 3;
    printf("i = %d, j = %d\n", i, j);
    return 0;
}

这时我们再编译、链接、执行一下:
i = 10, j = 3

i=、,、空格和j=全都原样输出了。此外需要注意的是:“输出控制符”和“输出参数”无论在“顺序上”还是在“个数上”一定要一一对应。

4) printf(“输出控制符 非输出控制符”,输出参数);

这实际上就是上面那个例子。这时候会有一个问题:到底什么是“输出控制符”,什么是“非输出控制符”?很简单,凡是以%开头的基本上都是输出控制符。

输出控制符
常用的输出控制符主要有以下几个:

在这里插入图片描述

%x、%X、%#x、%#X 的区别

一定要掌握 %x(或 %X 或 %#x 或 %#X),因为调试的时候经常要将内存中的二进制代码全部输出,然后用十六进制显示出来。下面写一个程序看看它们四个有什么区别:

# include <stdio.h>
int main(void)
{
    
    
    int i = 47;
    printf("%x\n", i);   
    printf("%X\n", i);   
    printf("%#x\n", i);   
    printf("%#X\n", i);   
    return 0;
}

在 VC++ 6.0 中的输出结果:
2f
2F
0x2f
0X2F

从输出结果可以看出:如果是小写的x,输出的字母就是小写的;如果是大写的X,输出的字母就是大写的;如果加一个#,就以标准的十六进制形式输出。

最好是加一个#,否则如果输出的十六进制数正好没有字母的话会误认为是一个十进制数呢!总之,不加#容易造成误解。但是如果输出 0x2f 或 0x2F,那么人家一看就知道是十六进制。而且%#x和%#X中,笔者觉得大写的比较好,因为大写是绝对标准的十六进制写法。

如何输出 %d、\ 和双引号

printf 中有输出控制符%d,转义字符前面有反斜杠\,还有双引号。那么大家有没有想过这样一个问题:怎样将这三个符号通过 printf 输出到屏幕上呢?

要输出%d只需在前面再加上一个%,要输出\只需在前面再加上一个\,要输出双引号也只需在前面加上一个\即可。程序如下:

# include <stdio.h>
int main(void)
{
    
    
    printf("%%d\n");
    printf("\\\n");
    printf("\"\"\n");
    return 0;
}

在 VC++ 6.0 中的输出结果是:
%d

“”

总结

printf与sprintf 是C语言中非常重要的函数。经过上面的学习我们发现,其实它并不难。只要多编程多练习,很快就能掌握。

猜你喜欢

转载自blog.csdn.net/weixin_43491077/article/details/109458216
今日推荐