输入与输出
标准库实现了简单的文本输入/输出模式。文本流由一系列行组成,每一行的结尾是一个换行符。最简单的输入输出机制是从标准输入一次读取一个字符或从标准输出一次写入一个字符,所以,有如下两个函数:
int getchar(void)
int putchar(int c)
在许多环境中,可以使用符号<来实现输入重定向,它将把标准输入替换为文件输入,如:
prog <infile
此外,在支持管道的系统上,使用管道也可以进行输入重定向:
otherprog | prog
这个命令将运行两个程序otherprog和prog,并将程序otherprog的标准输出通过管道重定向到程序prog的标准输入上。类似的,可以使用下面两个方法进行输出重定向:
prog >输出文件名
prog | anotherprog
格式化输入输出
输出函数printf将内部数值转换为字符的形式。该函数的原型为:
int printf(char *format,arg1,arg2,...)
格式字符串包含两种类型的对象:普通字符和转换说明。在输出时,普通字符将原样不动地复制到输出流中,而转换说明并不直接输出到输出流中,而是用于控制printf的参数的转化和打印。每个转化说明都由一个百分号字符开始,并以一个转换字符结束。在字符%和转换字符中间可能依次包含下列组成部分:
- 负号,用于指定被转换的参数按照左对齐的形式输出。
- 数,用于指定最小字段宽度。
- 小数点,用于将字段宽度和精度分开。
- 数,用于指定精度。
- 字母h或l,字母h表示将整数作为short类型打印,字母l表示将整数作为long类型打印。
转换字符有如下的一些:d,i,o,x,u,c,s,f,e,g,p,%。
变长参数表
如果不了解对底层理解,对于printf和scanf的函数实现会比较惊讶。关键的问题时,我们如何得到后面的参数,这里为了简单起见,我们假设所有的参数都是通过栈来传递的,这样,大致的思路是这样的,通过第一个参数,我们知道了参数的起始位置,使用一个指针记录,然后我们根据格式转换符的说明,我们知道了下一个参数的大小和格式,所以我们可以通过指针的偏移和解引用得到这个值。如果是通过寄存器传值,估计要复杂一点,但是思想是一样的。在标准库中,提供了通用的函数,下面以一个minprintf函数来说明这个过程:
#include<stdio.h>
#include<stdarg.h>
#include<stdlib.h>
void minprintf(char *fmt,...){
va_list ap;/* 依次指向各个参数 */
int ival;
double dval;
char *sval;
va_start(ap,fmt);/* 得到第一个参数的位置 */
while(*fmt){
if(*fmt != '%'){
putchar(*fmt);
fmt++;
continue;
}
switch(*++fmt){
case 'd':
/* 根据类型和指针,就可以取得下一个参数 */
ival = va_arg(ap,int);
printf("%d",ival);
break;
case 'f':
dval = va_arg(ap,double);
printf("%f",dval);
break;
case 's':
sval = va_arg(ap,char *);
printf("%s",sval);
break;
default:
putchar(*fmt);
break;
}
fmt++;
}
va_end(ap);
}
int main(int argc, char const *argv[])
{
int ival = 10;
double dval = 12.34;
char *sval = "hello world";
printf("ival = %d,dval = %f,sval = %s\n",ival,dval,sval);
minprintf("ival = %d,dval = %f,sval = %s\n",ival,dval,sval);
system("pause");
return 0;
}
格式化输入
输入函数scanf对应于输出函数printf,它在于后者相反的方向上提供同样的转换功能。scanf的函数原型为:
int scanf(char *format,...)
格式串通常都包含转换说明,用于控制输入的转换。格式串可能包含下列部分:
- 空格或制表符,在处理过程中将被忽略。
- 普通字符,用于匹配输入流中下一个非空白符字符。
- 转换说明,依次由一个%,一个可选的禁止字符*,一个可选的数值(指定最大字段宽度),一个可选的h,l或L字符(指定目标对象的宽度)以及一个转换字符组成)。
转换字符指定对输入字段的解释,对应的参数必须是指针,转换字符有如下一些:d,i,o,u,x,c,s,e,f,g,%。
文件访问
对文件的读写和对标准输入输出流是一样的,只不过需要先打开文件。打开文件的函数原型为:
FILE *fopen(char *name,char *mode);
FILE指针称为文件指针,它指向一个包含文件信息的结构,这些信息包含:缓冲区的位置,缓冲区中当前字符的位置,文件的读或写状态,是否出错或者是否已经到达文件结尾等等。启动一个C语言程序时,操作系统负责打开3个文件的指针给该程序,这3个文件分别是标准输入,标准输出和标准错误,相应的文件指针为stdin,stdout和stderr。对于文件的读写,提供的函数和读写标准输入输出类似:
int getc(FILE *fp)
int putc(int c,FILE *fp)
int fscanf(FILE *fp,char *format,...)
int fprintf(FILE *fp,char *format,...)
char *fgets(char *line,int maxline,FILE *fp)
int fputs(char *line,FILE *fp)
下面试一个例子,演示了从文件中读取数据,并打印到屏幕上:
#include<stdio.h>
#include<stdlib.h>
void filecopy(FILE *ifp,FILE *ofp){
char c;
while( (c = getc(ifp)) != EOF){
putc(c,ofp);
}
}
int main(int argc, char const *argv[])
{
char *fileName = "used/bit.c";
FILE *file;
if((file = fopen(fileName,"r")) != NULL){
filecopy(file,stdout);
}else{
printf("open file fail\n");
}
system("pause");
return 0;
}