格式化输出的函数有printf、sprintf和snprintf等,功能略有不同,使用方法大同小异,本章节我们先以printf为例。
对于 printf 函数,相信大家并不陌生。之所以称它为格式化输出函数,该函数的声名如下:
int printf(const char *format, ...);
大家看到printf函数的声明就会有点懵,它参数的写法与我们之前学到的函数知识不一样,printf函数是一个“可变参数函数”(即函数参数的个数是可变的),可变参数函数的知识以后再介绍,现在只要知道怎么使用就行了。
printf函数的参数的个数和类型都是可变的,每一个参数的输出格式都有对应的格式说明符与之对应,从格式串的左端第 1 个格式说明符对应第 1 个输出参数,第 2 个格式说明符对应第 2 个输出参数,第 3 个格式说明符对应第 3 个输出参数,以此类推。
其中,格式说明符的形式如下(方括号 [] 中的项为可选项):
%[flags][width][.prec]type
它用以表示输出数据的类型,以下是常用类型的汇总,不常用的就不列了。
%hd、%d、%ld 以十进制、有符号的形式输出 short、int、long 类型的整数。
%hu、%u、%lu 以十进制、无符号的形式输出 short、int、long 类型的整数
%c 输出字符。
%lf 以普通方式输出double(float弃用,long doube无用)。
%e 以科学计数法输出double。
%s 输出字符串。
%p 输出内存的地址。
以上输出数据的知识在之前介绍数据类型的时候已演示过,这里就不举例了。
它用于控制输出内容的宽度。
printf("=%12s=\n","abc"); // 输出= abc= printf("=%12d=\n",123); // 输出= 123= printf("=%12lf=\n",123.5); // 输出= 123.500000=
flags它用于控制输出内容的对齐方式。
不填或+:输出的内容右对齐,这是缺省的方式,上一小节就是右对齐的示例。
-:输出的内容左对齐。
printf("=%-12s=\n","abc"); // 输出=abc = printf("=%-12d=\n",123); // 输出=123 = printf("=%-12f=\n",123.5); // 输出=123.500000 =
如果输出的内容是整数或浮点数,并且对齐的方式是右对齐,可以加0填充,例如:
printf("=%012s=\n","abc"); // 输出= abc= printf("=%012d=\n",123); // 输出=000000000123= printf("=%012f=\n",123.5); // 输出=00123.500000=
从上面第一行代码的结果看出,输出的内容不是整数或浮点数,是字符串,不能在前面填0。
左对齐的时候,能在整数或浮点数的后面补0吗?浮点数最多可以补到6位,整数不行,为什么?您的存款能在后面补0吗?
如果输出的内容是浮点数,它用于控制输出内容的精度,也就是说小数点后面保留多少位,后面的数四舍五入。
printf("=%12.2lf=\n",123.5); // 输出= 123.50= printf("=%.2lf=\n",123.5); // 输出=123.50= printf("=%12.2e=\n",123500000000.0); // 输出= 1.24e+11= printf("=%.2e=\n",123500000000.0); // 输出=1.24e+11=
int printf(const char *format, ...); int sprintf(char *str, const char *format, ...); int snprintf(char *str, size_t size, const char *format, ...);
功能:printf是把结果输出到屏幕,sprintf把格式化输出的内容保存到字符串str中,snprintf的n类似于strncpy中的n,意思是只获取输出结果的前n-1个字符,不是n个字符。
在之前的章节中,介绍过把字符串转换为整数和浮点数据的库函数,C语言没有提供把整数和浮点数转换为字符串的库函数,而是采用sprintf和snprintf函数格式化输出到字符串。
示例(book98.c)
/* * 程序名:book98.c,此程序演示格式化输出sprintf和snprintf函数。 * 作者:C语言技术网(www.freecplus.net) 日期:20190525 */ #include <stdio.h> #include <string.h> int main() { char str[301]; // 格式化输出到str中 sprintf(str,"%d,%c,%f,%s",10,'A',25.97,"一共输入了三个数。"); printf("%s\n",str); // 格式化输出到str中,只截取前7个字符 snprintf(str,8,"%d,%c,%f,%s",10,'A',25.97,"一共输入了三个数。"); printf("%s\n",str); }
运行结果
程序运行第二行只输出了6个字符,注意,snprintf函数在unix和windows平台下的表现略有不同,在windows平台下,第二行会输出7个字符。
在我们之前学习的过程中,编写的程序的功能很简单,一句代码很短,但是在实际开发中,函数参数往往很长很多,一句代码可能会很长,需要用多行才能书写。
如果我们在一行代码的行尾放置一个反斜杠,c语言编译器会忽略行尾的换行符,而把下一行的内容也算作是本行的内容。这里反斜杠起到了续行的作用。
strcpy(str,"aaaaaaaaaa\ bbbbbbbbb");
如果我们不使用反斜杠,当我们试图初始化一个跨多行的字符串时,c语言编译器可能会发出警告或错误,如下面的语句是不正确的。
strcpy(str,"aaaaaaaaaa bbbbbbbbb");
C语言中还有字符串多行书写的方法,那就是将它写个多个字符串,C语言编译器会自动将这些字符串连接起来,如下:
strcpy(str,"aaabbbccc"); printf("str=%s=\n",str); // 输出str=aaabbbccc= strcpy(str,"aaa""bbb""ccc"); printf("str=%s=\n",str); // 输出str=aaabbbccc= strcpy(str,"aaa"\ "bbb"\ "ccc"); printf("str=%s=\n",str); // 输出str=aaabbbccc= sprintf(str,"aaabbbccc"); printf("str=%s=\n",str); // 输出str=aaabbbccc= sprintf(str,"aaa""bbb""ccc"); printf("str=%s=\n",str); // 输出str=aaabbbccc= sprintf(str,"aaa"\ "bbb"\ "ccc"); printf("str=%s=\n",str); // 输出str=aaabbbccc=
以上每段代码的输出结果完全一样,表达式:"aaa" "bbb" "ccc" 实际上相当于 "aaabbbccc"。
把字符串很长,参数很多的代码用多行书写,可以使程序代码结构更清晰,以下代码是我实际开发中用到的一句代码,这还不算长的。
1)编写示例程序,把本章节介绍的知识点全部演示一遍,用程序演示可以加深您的理解和映象。
2)编写一个程序,把超女结构体数据拼成一个XML字符串,超女结构体如下:
struct st_girl { char name[51]; // 姓名 int age; // 年龄 int height; // 身高,单位:cm double weight; // 体重,单位:kg char sc[31]; // 身材,火辣;普通;飞机场 char yz[31]; // 颜值,漂亮;一般;歪瓜裂枣 };
XML格式的字符串如下:
<name>西施</name><age>18</age><height>168</height><weight>48.5</weight><sc>火辣</sc><yz>漂亮</yz>
3)编写解析XML字符串的函数族,解析XML字符串。
函数声明:
// 解析XML字符串的函数族,支持int、char *和double三种类型。 // 返回值:0-成功,-1-失败。 int GetXMLBuffer_Int(const char *in_XMLBuffer,const char *in_FieldName,int *out_Value); int GetXMLBuffer_Str(const char *in_XMLBuffer,const char *in_FieldName,char *out_Value); int GetXMLBuffer_Double(const char *in_XMLBuffer,const char *in_FieldName,double *out_Value);
in_XMLBuffer,XML格式的字符串,如下:
<name>西施</name><age>18</age><height>168</height><weight>48.5</weight><sc>火辣</sc><yz>漂亮</yz>
in_FieldName,字段的标签名。
out_Value,获取内容存放的变量的指针。
返回值,0-成功,-1-失败。
调用示例:
char strXMLBuffer[1024]; memset(strXMLBuffer,0,sizeof(strXMLBuffer)); strcpy(strXMLBuffer,"<name>西施</name><age>18</age><height>168</height><weight>48.5</weight><sc>火辣</sc><yz>漂亮</yz>"); char name[51]; memset(name,0,sizeof(name)); int age=0; double weight=0; GetXMLBuffer_Str(strXMLBuffer,"name",name); // name的内容将是"西施" GetXMLBuffer_Int(strXMLBuffer,"age",&age); // age的内容将是18 GetXMLBuffer_Double(strXMLBuffer,"weight",&weight); // weight的内容将是48.5
/* * 程序名:task.c,此程序演示XML格式字符串的生成和解析。 * 作者:C语言技术网(www.freecplus.net) 日期:20200510 */ #include <stdio.h> #include <string.h> struct st_girl { char name[51]; // 姓名 int age; // 年龄 int height; // 身高,单位:cm double weight; // 体重,单位:kg char sc[31]; // 身材,火辣;普通;飞机场 }; // 解析XML字符串的函数族,支持int、char *和double三种类型。 // 返回值:0-成功,-1-失败。 int GetXMLBuffer_Int(const char *in_XMLBuffer,const char *in_FieldName,int *out_Value); int GetXMLBuffer_Str(const char *in_XMLBuffer,const char *in_FieldName,char *out_Value); int GetXMLBuffer_Double(const char *in_XMLBuffer,const char *in_FieldName,double *out_Value); int main() { struct st_girl stgirl; memset(&stgirl,0,sizeof(struct st_girl)); strcpy(stgirl.name,"西施"); stgirl.age=18; stgirl.height=168; stgirl.weight=45.5; strcpy(stgirl.sc,"火辣"); char str[301]; memset(str,0,sizeof(str)); sprintf(str,\ "<name>%s</name><age>%d</age><height>%d</height><weight>%.2lf</weight><sc>%s</sc>",\ stgirl.name,stgirl.age,stgirl.height,stgirl.weight,stgirl.sc); printf("=%s=\n",str); memset(&stgirl,0,sizeof(struct st_girl)); GetXMLBuffer_Str(str,"name", stgirl.name); GetXMLBuffer_Int(str,"age" ,&stgirl.age); printf("name=%s,age=%d\n",stgirl.name,stgirl.age); } // <name>西施</name><age>18</age><height>168</height><weight>45.50</weight><sc>火辣</sc> int GetXMLBuffer_Str(const char *in_XMLBuffer,const char *in_FieldName,char *out_Value) { if (out_Value==0) return -1; // 如果out_Value是空地址,返回失败。 char *start=0,*end=0; char m_SFieldName[51],m_EFieldName[51]; // 字段的开始和结束标签。 int m_NameLen = strlen(in_FieldName); // 字段名长度。 memset(m_SFieldName,0,sizeof(m_SFieldName)); memset(m_EFieldName,0,sizeof(m_EFieldName)); snprintf(m_SFieldName,50,"<%s>",in_FieldName); snprintf(m_EFieldName,50,"</%s>",in_FieldName); start=0; end=0; start = (char *)strstr(in_XMLBuffer,m_SFieldName); // 字段开始标签的位置 if (start != 0) { end = (char *)strstr(start,m_EFieldName); // 字段结束标签的位置。 } if ((start==0) || (end == 0)) return -1; int m_ValueLen = end - start - m_NameLen - 2; // 字段值的长度。 strncpy(out_Value,start+m_NameLen+2,m_ValueLen); // 获取字段的值。 out_Value[m_ValueLen]=0; return 0; } int GetXMLBuffer_Int(const char *in_XMLBuffer,const char *in_FieldName,int *out_Value) { char strvalue[51]; memset(strvalue,0,sizeof(strvalue)); if (GetXMLBuffer_Str(in_XMLBuffer,in_FieldName,strvalue)!=0) return -1; (*out_Value)=atoi(strvalue); return 0; }
C语言技术网原创文章,转载请说明文章的来源、作者和原文的链接。
来源:C语言技术网(www.freecplus.net)
作者:码农有道
C语言技术网(www.freecplus.net),粤ICP备19156379号