C IO(格式化输入输出)
INPUT
int printf ( const char * format, ... );
格式化输出格式如下:
%[flags][width][.precision][length]specifier
一些比较实用的标记:
flags:- 左对齐,默认为右对齐
+ 显示正负号,默认只显示负号
# 显示前缀标记,如和0x结合使用,输出会在数值前面加上0x
0 当指定输出width时,默认以空格填充,0指示以0 填充
width: 指定输出的有效位。
specifiers | |||||||
|---|---|---|---|---|---|---|---|
| length | d i | u o x X | f F e E g G a A | c | s | p | n |
| (none) | int | unsigned int | double | int | char* | void* | int* |
| hh | signed char | unsigned char | signed char* | ||||
| h | short int | unsigned short int | short int* | ||||
| l | long int | unsigned long int | wint_t | wchar_t* | long int* | ||
| ll | long long int | unsigned long long int | long long int* | ||||
| j | intmax_t | uintmax_t | intmax_t* | ||||
| z | size_t | size_t | size_t* | ||||
| t | ptrdiff_t | ptrdiff_t | ptrdiff_t* | ||||
| L | long double | ||||||
specifier: p 接收一个指针,并打印其地址
一个注意的地方:
由于整数和浮点数存储机制不同,以下调用会输出错误的值:
printf("%d",23.0);//输出为0
int fprintf ( FILE * stream, const char * format, ... )
和printf相似,只不过输出有stdout变成了流
int sprintf ( char * str, const char * format, ... );
int snprintf ( char * s, size_t n, const char * format, ... );//c11 added
输出定向为字符串,与snprintf相比,sprintf需要给str预留足够的空间,建议使用snprintf
int vprintf ( const char * format, va_list arg );
输出va_list类型的参数到stdout,与printf的原理相同,
讲一下什么是参数列表va_list(下面属于扯淡)
如printf的原型 int printf ( const char * format, ... );有时候我们编写函数的时候,有可能你事先并不知道需要传递传递多少个参数,C允许我们用...代表未知个数的参数,
它有可能是空的,或者1个或者多个参数。那么我们怎么知道到底有多少个参数,每个参数的类型是什么,答案是格式化字符串。
就是我们平时使用的诸如“%d %f %c”,从字符串中,我们知道,...应该总共有三个参数,一个int ,一个float,一个char
当然也有可能还有第三个或者更多参数,也或者,第一个根本不是int,这属于使用者传参错误的情况,应该避免。
标准库提供了方法获取每个参数的方法,但是其参数个数及类型还是需要你去分析。
下面是个例子:
#include <stdio.h> /* printf */
#include <stdarg.h> /* va_list, va_start, va_arg, va_end */
int FindMax (int n, ...)
{
int i,val,largest;
va_list vl;
va_start(vl,n);
largest=va_arg(vl,int);
for (i=1;i<n;i++)
{
val=va_arg(vl,int);
largest=(largest>val)?largest:val;
}
va_end(vl);
return largest;
}
int main ()
{
int m;
m= FindMax (7,702,422,631,834,892,104,772);
printf ("The largest value is: %d\n",m);
return 0;
}
上面FindMax第一个参数是7,简化了从format string中分析参数个数的步骤,而参数全部为int简化了分析参数类型。
更近一步,看看va_list 和va_start va_end是个什么东东,
下面是这些东东在x86下面的一个实现
- typedef char * va_list;
- #define _INTSIZEOF(n) \
- ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) )
- #define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
- #define va_arg(ap,t) \
- ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
- #define va_end(ap) ( ap = (va_list)0 )
_INTSIZEOF 是将n以int对齐的算式,x86以int对齐。
回到程序,调用va_start (args, format)后,则args指向了format之后的地址,va_start相当于初始化args,
va_arg 从args中取出t类型的数据。代码比较简单,
va_end将args赋为NULL。
int vfprintf ( FILE * stream, const char * format, va_list arg );
与vprintf的区别是输出为文件。
int vsprintf (char * s, const char * format, va_list arg );
输出到字符串,s需要有足够的大小。
int vsnprintf (char * s, size_t n, const char * format, va_list arg );//c11
vsprintf 的安全版
INPUT
int scanf ( const char * format, ... );
从stdin读取格式化输入。需要注意的是scanf以键盘\n结束输入,以空格分割token。
int fscanf ( FILE * stream, const char * format, ... );
从文件中获取格式化字符串。
int sscanf ( const char * s, const char * format, ...);
从字符串中获取。
int vscanf ( const char * format, va_list arg );//c11
int vsscanf ( const char * s, const char * format, va_list arg );//c11
int vfscanf ( FILE * stream, const char * format, va_list arg );/c11
作用类似,只不过格式化数据来源不同,分别为stdin,字符串,文件。

浙公网安备 33010602011771号