详解C语言输入/输出函数

错误报告

perror函数简化向用户报告特定错误的过程。它的原型定义于studio.h,如下:

  void perror(char const *message);

如果message不是NULL并且指向一个非空的字符串,perror函数就打印出这个字符串,后面跟一个分号和一个空格,然后打印出一条用于解释errno(标准库函数用一个外部整型变量来保存错误码)。

终止执行

exit函数用来终止一个程序,它的原型定义于stdlib.h,如下:

  void exit(int status);

status参数返回给操作系统,用于提示程序是否正常完成。这个值和main函数返回的整型状态值一样,预定义符号EXIT_SUCCESS和EXIT_FALIURE分别提示程序的终止成功还是失败,虽然程序可以使用其他值,但它们的具体含义取决于编译器。

注意这个函数没有返回值。当exit函数结束时,程序已经消失,所以它无处可返。

标准I/O函数库

头文件stdio.h包含了与ANSI函数库的I/O部分有关的声明。

就C程序而言,所有的I/O操作只是简单地从程序移进移出字节的事情,这些字节流便被称为

流I/O总览

I/O函数以三种基本的形式处理数据:单个字符,文本行和二进制数据对于每一种都有特定的函数对他们进行处理。
                  执行字符,文本行和二进制I/O的函数

数据类型 输 入 输 出 描 述
字符 getchar putchar 读取(写入)单个字符
文本行 gets puts 文本行未格式化的输入(输出)
文本行 scanf printf 格式化的输入(输出)
二进制数据 fread fwrite 读取(写入)二进制数据

打开流

fopen用于打开一个特定的文件,并把一个流和这个文件相关联,它的原型如下:

File *fopen(char const *name,char const *mode);

参数name是打开的文件名,mode是打开文件的方式(见下表),File*类型的变量用来保存fopen的返回值,并不影响哪个文件被打开。

数据格式 读 取 写 入 添 加
文本 "r" "w" "a"
二进制 "rb" "wb" "ab"

如果一个文件打开是用于读取的,那么他应该是原先已经存在的;
  如果一个文件打开是用于写入的,那么它原先的内容就会被删除,如果它原先不存在,那么就创建一个新文件;
  如果一个文件打开用于天机的文件原先并不存在那么它将被创建,如果它原先已经存在,那么它原先的内容不会被删除,无论那种情况都只能在文件的尾部写入。
  freopen用于打开特定(重新打开)的文件流,它的原型如下:

File *freopen(char const *filename,char const *mode,File *stream);

最后一个参数就是要打开的流,它可能是一个先前用fopen函数打开的流,也可能是stdin,stdout或是stderr。

关闭流

int fclose(File *f);

对于输出流,fclose函数在文件关闭前刷新缓冲区,如果它执行成功,fclose返回零值,否则返回EOF

字符I/O

字符输入是由getchar函数家族执行的,他们的原型如下:

int fgetc(File *stream);
int getc(File *stream);
int getchar(void);

这些函数都用于读取字符,但它们都返回一个int型但是不是char型。

字符输出是由putchar函数家族执行的,它们的原型如下:

int fputc(int character,File *stream);
int putc(int character,File *stream);
int putchar(int character);

fgetc和fputc都是真正的函数,但getc,putc,getchar,putchar,都是通过宏定义的。

撤销字符I/O

函数原型如下:

int ungetc(int character,File*stream);

函数ungetc把一个先前读入的字符返回流中,这样它可在以后被重新读入。

未格式化的行I/O

行I/O的执行方式分为两类——未格式化或格式化,这两种形式都用于操作字符串。
gets和puts家族函数的原型如下:

char *fgets(char *buffer,int buffer_size,File *stream);
char gets(char *buffer);

int fputs(char *buffer,File *stream);
int puts(char const *buffer);

fgets函数从制定的stream中读取字符并把它们复制到buffer中,当它读取到一个换行符并存储到缓冲区之后就不在读取。
fgets函数从制定的流中读取buffer_size字符和一个NULL字符(尾零)。
fgets函数返回它的第一个参数(执行缓冲区的指针),如果在未读取任何字符就达到文件尾,fgets返回NULL。
fputs函数的缓冲区必须包含一个以NULL结尾的字符串,所以该函数没有字符串的长度参数,这个字符串是逐字写入的,如果它不包含一个换行符,就不会写入换行符。如果包含好几个换行符,所有的换行符都会被写入。

函数gets和puts几乎和函数fgets和fputs相同,区别在于:
1.gets在读取一行输入时,它并不在缓冲区中存储结尾的换行符
2.puts在写入一个字符串时,它在字符串写入之后向输出在添加一个换行符

格式化的I/O

scanf和printf函数家族负责格式化行的输入与输出。

scanf家族

scanf函数家族的原型中的省略号表示一个可变长的指针列表。从输入转换而来的值逐个存储到这些指针参数所指向的内存位置。

int fscanf(File *stream,char const *fomat,...);
inr scanf(char const *fomat,...);
int sscanf(char const *string,char const *format,...);

这些函数都是从输入源读取字符并根据format字符串个出的格式码对他们进行转换,fscanf的输入源就是stream(流),scanf的输入源就是stdin,而sscanf则从第一个参数给出的字符串中读取字符。

当格式化字符串达到末尾或者读取的输入不在匹配格式字符串所指定的类型事,输入就停止,在任何一种情况下,被转换的输入值的数目作为函数的返回值。如果在任何输入值被转换之前就达到尾部,函数就返回常量值EOF

scanf格式代码

scanf函数家族中的format字符串可以是下列内容:

  • 空白字符——他们与输入中的零个或多个空白符匹配,在处理过程中被忽略。
  • 格式代码——它们指定函数如何解释接下来的输入字符。
  • 其他字符——当任何其他字符出现在格式字符串中,下一个输入字符必须与他匹配。如果匹配,该输入字符随后被丢弃,如果不匹配,函数就不在读取直接返回。

scanf函数家族的格式字符串通常以一个%号开始,有下列内容组成:

  • 可选的星号(*)——将转换后的值丢弃而不是存储;
  • 一个可选的宽度——限制输入字符的个数,如果宽度未给出,函数就连续输入知道遇见输入中的下一个空白字符;
  • 一个可选的限定符——修改有些格式代码的含义;
  • 格式代码。

printf函数家族

printf函数家族用于创建格式化输出。

int fprintf(File *stream,char const *format,...);
int printf(char connst *format,...);
int sprintf(char *buffer,char const *format,...);

prinnt结果输出送到标准输出(stdout)
fprintf可以使用任何输出流
sprintf把它的的结果作为一个NULL结尾的字符串存储到指定的buffer缓冲区,而不是流;

printf家族函数的格式码通常以%开始由下列要素组成:

  • 零个或多个标志字符——修改转换的执行方式;
  • 一个可选的最小字段——如果值的字符小于字段宽度,就对它进行填充增加长度,标志决定填充使用空白还是零以及它出现在值得左边还是右边;
  • 一个可选的精度——指定将出现结果中的最小的数字个数并覆盖零标志,精度缺省为零;
  • 一个可选的修改字符;
  • 转换类型;

二进制I/O

  把数据写入到文件效率最高的是二进制形式写入。二进制输出避免了在数值转换成字符串过程的所涉及的开销和精度损失。
  fread函数用于读取二进制数据,fwrite函数用于写入二进制,他们的原型如下:

size_t  fread(void *bffer,size_t size,sizet_cout,File *stream);
size_t  fwrite(void *bffer,size_t size,sizet_cout,File *stream);

  buffer是一个指向用于保存数据的内存位置的数据,size是缓冲区每个元素的字节数,count是读取或写入的元素数,stream是数据读取或写入的流。
  函数的返回值是实际读取或写入的元素数目

刷新或定位函数

  • 函数fflush——它迫使一个输出流的缓冲区内的数据进行物理写入,不管它是否已经写满,原型如下:
int fflush(File *stream);

  当我们需要立即把数据缓冲区的内容吴莉莉写入时,就可以使用这个函数。

C语言支持随机I/O,也就是以任意的顺序访问文件中的不同位置,随机访问时通过在读取或写入前定位到文件中所需要的位置来实现的,ftell和fseek函数来实现这项操作。

long ftell(File *stream);
int fseek(File *stream,long offset,int from);

ftell函数返回当前流的位置,也就是说,下一个读取或写入将要开始的位置距离文件起始位置的偏移量。
ftell函数的返回值总是可以作为函数fseek的参数,作为一个距离文件起始位置的偏移量。
函数fseek允许你在一个流中定位,这项操作将改变下一个读取或写入的位置,它的第二第三个参数如下表。

数据格式 你将定位到的是
SEEK_SET 从流的起始位置起offset个字节,offset必须是一个非负值
SEEK_CUR 从流的当前位置起offset个字节,offset可正可负
SEEK_END 从流的尾部位置起offset个字节,offset可正可负,如果是正直将定位到文件尾的后面

改变缓冲方式

  在流上的缓冲凡是有时候并不适合,下面两个函数可以改变流的缓冲方式,这两个函数只有当指定的流被打开还没有在它上面执行任何操作时才能够被调用。

void setbuf(File *stream,char *buf);
int setvbuf(File *stream,char *buf,int mode,size_t size);

setbuf函数设置了一个数组,用于对流进行缓冲。这个数组的长度必须是BUFSIZE(它在stdio中定义)如果以一个NULL参数调用这个函数,setbuf会将这个流关闭。
setvbuf函数中的mode参数用于指定缓冲类型,_IOFBF指定一个完全缓冲流,_IONBF指定一个不缓冲的流,_IOLBF指定一个行缓冲流(当一个换行符写入到缓冲区时,缓冲区就进行刷新)

文件操纵函数

  有两个函数用于操纵文件但不执行任何输入/输出操作,执行成功函数返回值为零,如果失败返回非零。

int remove(char const *filename);
int rename(char const *oldname,char const *newname);

函数remove用于删除一个指定的文件呢,文件处于打开状态,其结果取决于编译器。
函数rename用于重命名文件名。

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

推荐阅读更多精彩内容

  • C/C++输入输出流总结 前两天写C++实习作业,突然发现I/O是那么的陌生,打了好长时间的文件都没有打开,今天终...
    LuckTime阅读 1,706评论 0 6
  • PHP常用函数大全 usleep() 函数延迟代码执行若干微秒。 unpack() 函数从二进制字符串对数据进行解...
    上街买菜丶迷倒老太阅读 1,347评论 0 20
  • php usleep() 函数延迟代码执行若干微秒。 unpack() 函数从二进制字符串对数据进行解包。 uni...
    思梦PHP阅读 1,980评论 1 24
  • 单例 单例是一种设计模式,确保一个类最多同时存在一个实例,并易于访问。 单例实现 1、私有构造方法 2、内部键静态...
    BruceLeeJ阅读 141评论 0 0
  • 又到了交作业的日子 实在不知道该写什么 这说明什么? 内心空空,没有可以表达的东西 思想懒惰,不愿意深入思考,并记...
    斜杠中年再学习阅读 500评论 0 51