输入与输出

标准库实现了简单的文本输入/输出模式。文本流由一系列行组成,每一行的结尾是一个换行符。最简单的输入输出机制是从标准输入一次读取一个字符或从标准输出一次写入一个字符,所以,有如下两个函数:

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;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • 本文内容非原创,你可以点击此处查看内容来源声明 输入/输出流 在Java API中,可以从其中读出一个字节序列的对...
    _gitignore阅读 2,520评论 0 0
  • 在C语言中,五种基本数据类型存储空间长度的排列顺序是: A)char B)char=int<=float C)ch...
    夏天再来阅读 3,320评论 0 2
  • 早上3点2分 我停靠的行囊被人偷窃 我彷徨的寻找警察 但是我却找不到如何拨打110 滑稽的搞笑 我在酒店的宾馆寻找...
    为你点一杯阳春面阅读 161评论 0 0
  • 今天又去听了一遍有关写作的讲座,这个课程一年前已经听过数次,可今天来听,又发现好几个必要且重要的部分被自己忽略了。...
    申湘黔阅读 286评论 2 3
  • 今天朋友还回来一本书,了凡四训。这本书是自己几年前看的,是看的第一本也是唯一一本关于佛学的书。 这本书对我的影响很...
    绽蕊向阳阅读 1,026评论 0 0