一、printf、fprintf 和sprintf函数
函数原型:
#include
int printf(const char *format, ...);
int sprintf(char *s, const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
函数说明:
printf系列函数能够对这种不同类型的参数进行格式编排和输出。format参数控制输出的格式。
printf函数,print format的简写,作用是把自己的输出送到标准输出。
sprintf函数,string print format的简写,作用是把自己的输出和一个结尾空字符写到作为参数传递过来的字符串s里。这个字符串必须足够容纳所有的输出数据。
fprintf函数,file print format的简写,作用是把自己的输出送到一个指定的文件流。
常用的转换控制符:
转换控制符 | 转换控制符说明 |
---|---|
%d,%i | 以十进制格式输出一个整数 |
%o,%x | 以八进制或十六进制格式输出一个整数 |
%c | 输出一个字符 |
%s | 输出一个字符串 |
%f | 输出一个(单精度)浮点数 |
%e | 以科学计数法格式输出一个双精度浮点数 |
%g | 以通用格式输出一个双精度浮点数 |
%% | 读取一个%字符 |
例:
char initial = ‘A’;
char *surname = "Matthew";
double age = 13.5;
printf("Hello Mr %c, %s, aged %g\n", initial, surname, age);
字段限定符:
字段限定符 | 说明 |
---|---|
%10s | 右对齐输出字符串 |
%-10s | 左对齐输出字符串 |
%10d | 右对齐输出整数 |
%-10d | 左对齐输出整数 |
%010d | 整数前的空位补0 |
%10.4f | 右对齐输出浮点数,精确到小数点后4位 |
%*s | 输出一个可变长度的字符串 |
"-":左对齐格式输出
“*”:可变字段宽度
0:0开头表示数据前面用0填充。
注意:
1.函数中的参数数目和类型必须与format字符串里的转换控制符匹配。
2.整数参数的类型可以用一个可选长度限定符来指定。它可以是h、l,例如%hd表示一个短整数,%ld表示这是一个长整数。使用gcc编译器,可以在编译命令中加-Wformat选项实现这一功能。
返回值说明:
printf函数返回的是输出的字符个数。sprintf的返回值里没有算上结尾的null空字符。如果发生错误,这些函数会返回一个负值并设置errno。
二、scanf、fscanf 和 sscanf函数
函数原型:
#include
int scanf(const char *format, ...);
int fscanf(FILE *stream, const char *format, ...);
int sscanf(const char *s, const char *format, ...);
函数说明:
scanf系列函数的工作方式与printf系列函数相似,作用是从一个文件流里读取数据,并把数据值放到以指针参数形式传递过来的地址处的变量中。它们也使用一个格式字符串来控制输入数据的转换,它所使用的许多转换控制符都与printf系列函数一样。
scanf函数,scan format的简写,作用是将读入的值保存到对应的变量中,这些变量必须是正确的,并且必须精确匹配格式字符串。否则,内存数据就可能遭到破坏,从而使程序崩溃。
转换控制符:
转换控制符 | 说明 |
---|---|
%d | 读取一个十进制整数 |
%o,%x | 读取一个八进制或十六进制整数 |
%c | 读取一个字符,它不会跳过起始的空白字符 |
%s | 读取一个字符串,它会跳过起始的空白字符 |
%f、%e、%g | 读取一个浮点数 |
%[] | 读取一个字符集合 |
%% | 读取一个%字符 |
%hd | 读入一个短整数 |
%ld | 读入一个长整数 |
%lg | 读入一个双精度浮点数 |
返回值说明:
scanf函数的返回值是它成功读取的数据项个数,如果在读第一个数据项时失败了,它的返回值就将是0.如果在匹配第一个数据项之前就已经到达了输入的结尾,它就会返回EOF。如果文件流发生错误,流错误标志就会被设置并且errno将被设置以指明错误类型。
注意:
1.输入的空白字符在进行数据转换时一般会被忽略。
2.以“*”开头的控制符表示对应位置上的输入数据将被忽略。这意味着,这个数据不会被保存,因此不需要使用一个变量来接收它。
3.使用%s控制符来扫描字符串时要小心,它会跳过起始的空白字符,在字符串里出现的第一个空白字符处停下来,所以最好用它来读取单词而不是一般意义上的字符串。此外,如果没有使用字段宽度限定符,它能够读取的字符串的长度是没有限制的,所以接收字符串必须有足够的空间来容纳输入流中可能的最长字符串。较好的选择是使用一个字段限定符,或者结合使用fgets和sscanf从输入读入一行数据,再对它进行扫描。这样可以避免可能被恶意用户利用的缓冲区溢出。
4.使用%[]控制符读取由一个字符集合中的字符构成的字符串。格式字符串%[A-Z]将读取一个由大写字母构成的字符串。如果字符串中第一个字符是,就表示将读取一个由不属于该字符集合中的字符构成的字符串。因此,读取一个其中带空格的字符串,并且在遇到第一个逗号时停止,可以用%[,]。
scanf系列函数缺点:
具体实现有漏洞。
使用不够灵活。
使用它们编写的代码不容易看出究竟正在解析什么。
可以尝试使用其他函数,如fread或fgets来读取输入行,再用字符串函数把输入分解成需要的数据项。
例:
#include
#include
int main()
{
int c;
FILE *in,*out;
in = fopen("file.in","r");
out = fopen("file.out","w");
while((c = fgetc(in)) != EOF)
{
FPUTC(C,out);
}
exit(0);
}
三、其他流函数
1.fgetpos函数
获取文件流的当前(读写)位置。
2.fsetpos函数
设置文件流的当前(读写)位置。
3.ftell函数
返回文件流当前(读写)位置的偏移量
4.rewind函数
重置文件流里的读写位置
5.frepoen函数
重新使用一个文件流
6.setvbuf函数
设置文件流的缓冲机制
7.remove函数
相当于unlink函数,但如果它的path参数是一个目录的话,其作用就相当于rmdir函数。
四、文件流错误
为了表明错误,许多stdio库函数会返回一个超出范围的值,比如空指针或EOF常数。错误由外部变量errno指出:
#include
extern int errno;
注意:很多函数都可能改变errno的值。它的值只有在函数调用失败时才有意义。必须在函数表明失败后立刻对其进行检查,应该总是在使用它之前先将它先复制到另一个变量中。
可以通过检查文件流的状态来确定是否发生了错误,或者是达到了文件尾。
函数原型:
#Include
int ferror(FILE *stream);
int feof(FILE * stream);
void clearerr(FILE *stream);
1.ferror函数说明
测试一个文件流的错误标识,如果该标识被设置就返回一个非零值,否则返回零。
2.feof函数说明
测试一个文件流的文件尾标识,如果该标志被设置就返回非零值。
3.clearerr函数说明
作用是清除由stream指向的文件流的文件尾标识和错误标识。它没有返回值,也未定义任何错误。可以通过使用它从文件流的错误状态中恢复。例如,在“磁盘已满”错误解决之后,继续开始写入文件流。
五、文件流和文件描述符
每个文件流都和一个底层文件描述符相关联。可以把底层的输入输出操作与高层的文件流操作混合使用,但不是很好,因为数据缓冲的后果难以预料。
函数原型:
#include
int fileno(FILE *stream);
FILE *fdopen(int fildes,const char *mode);
1.fileno函数
作用是确定文件流使用的是哪个底层文件描述符。它返回指定文件流使用的文件描述符,如果失败就返回-1.如果你需要对一个已经打开的文件流进行底层访问时(例如,对它调用fstat),这个函数会很有用。
2.fdopen函数
操作方式与fopen函数一样,只是fdopen的参数不是一个文件名,而是一个底层的文件描述符。如果已经通过open系统调用创建了一个文件(可能是出于为了更好地控制其访问权限的目的),但又想通过文件流来对它进行写操作,这个函数就很有用了。fdopen函数的mode参数与fopen函数的完全一样,但它必须符合该文件再最初打开是所设定的访问模式。fdopen返回一个新的文件流,失败时返回NULL。