当前位置: 首页 > news >正文

C语言基础 — ( C语言库函数<stdio.h>——C标准的内容)

欢迎小伙伴的点评✨✨ 本篇章系列是对C语言的深度思考和总结、关于C语言内容会持续更新

文章目录

  • 前言
  • 1、 输入/输出 <stdio.h>
    • 1.1、 简介
    • 1.2、 流
    • 1.3、 文件
    • 1.4、 对文件的操作
      • 1.4.1、函数 remove
      • 1.4.2、函数 rename
      • 1.4.3、函数 tmpfile
      • 1.4.4、函数 tmpnam
    • 1.5、文件访问函数
      • 1.5.1、函数 fclose
      • 1.5.2、函数 fflush
      • 1.5.3、函数 fopen
      • 1.5.4、函数 freopen
      • 1.5.5、函数 setbuf
      • 1.5.6、函数 setvbuf
    • 1.6、格式化的输入输出函数
      • 1.6.1、 函数 fprintf
      • 1.6.2、 函数 fscanf
      • 1.6.3、 函数 printf
      • 1.6.4、 函数 scanf
      • 1.6.5、 函数 sprintf
      • 1.6.6、 函数 sscanf
      • 1.6.7、 函数 vfprintf
      • 1.6.8、 函数 vprintf
      • 1.6.9、 函数 vsprintf
    • 1.7、字符输入/输出函数
      • 1.7.1、函数 fgetc
      • 1.7.2、函数 fgets
      • 1.7.3、函数 fputc
      • 1.7.4、函数 fputs
      • 1.7.5、函数 getc
      • 1.7.6、函数 getchar
      • 1.7.7、函数 gets
      • 1.7.8、函数 putc
      • 1.7.9、函数 putchar
      • 1.7.10、函数 puts
      • 1.7.11、函数ungetc
    • 1.8、直接输入/输出函数
      • 1.8.1、函数 fread
      • 1.8.2、函数 fwrite
    • 1.9、文件定位函数
      • 1.9.1、函数 fgetpos
      • 1.9.2、函数 fseek
      • 1.9.3、函数 fsetpos
      • 1.9.4、函数 ftell
      • 1.9.5、函数 rewind
    • 1.10、错误处理函数
      • 1.10.1、函数 clearerr
      • 1.10.2、函数 feof
      • 1.10.3、函数 ferror
      • 1.10.4、函数 perror
  • 二、总结


前言

头文件<stdio.h>声明了很多执行输入输出的函数。几乎所有的程序都要执行输出操作,所以这个头文件被广泛使用。事实上,它是最早出现在C标准库中的头文件之一。这个头文件比其他任何头文件声明的函数都要多。同时由于实现这些函数机制很复杂,因此它也需要更多的说明。


1、 输入/输出 <stdio.h>

1.1、 简介

头文件 <stdio.h>声明了3种类型、一些宏和很多执行输入输出的函数。
声明的类型有 size_t
FILE
它是一个对象类型,可以记录控制流需要的所有信息,包括它的文件定位符、指向相关缓冲(如果有的话)的指针,记录是否发生了读/写错误的错误指示符和记录文件是否结束的文件结束符;
fpos_t
它是一个对象类型,可以唯一指定文件中的每一个位置所需的所有信息。
声明的宏有 NULL ;
_IOFBF
_IOLBF
_IONBF
它们展开为具有不同值的整值表达式,适合作为函数setvbuf 的第三个参数使用;
BUFSIZ
它展开为一个整值常量表达式,是指setbuf 函数使用的缓冲的大小;
EOF
它展开为一个负的整值常量表达式,该表达式由几个函数返回来说明文件的结束,即一个流输入结束了;
FOPEN_MAX
它展开为一个整值常量表达式,表示实现支持的可以同时打开的文件数目的最小。
FILENAME_MAX
它展开为一个整值常量表达式,表示一个char 类型的数组的大小,这个数组可以保存实现可以打开的最长的文件名串。
L_tmpnam
它展开为一个整值常量表达式,表示一个char 类型数组的大小,这个数组可以保存tmpnam 函数生成的临时文件名串。
SEEK_CUR
SEEK_END
SEEK_SET
它们展开为具有不同值的整值常量表达式,适合作为 fseek 函数的第三个参数使用;
TMP_MAX
它展开为一个整值常量表达式,表示 tmpnam 函数可以生成的单独文件名最小数目。
stderr
stdin
stdout
它们是 指向FILE的指针 类型的表达式,分别指向与标准错误流,标准输入流和标准输出流相关的FILE对象。

1.2、 流


不管是读出还是写入物理设备,例如终端和磁带驱动器,或者不管是读出还是写入到结构化存储设备支持的文件,输入和输出都和逻辑数据流相对应,这些逻辑数据流的属性比各种各样的输入输出更加统一。C语言支持两种形式的映射,文本流和二进制流。
文本流
文本流是组成文本行的有序字符序列,每一行都由零个或者多个字符加上一个标志结束的换行符组成。最后一行是否需要结束的换行符是由实现定义的。输入输出时可能必须添加、修改或者删除一些字符来和宿主环境中表示文本的不同约定一致。因此,流中的字符和外部表示的字符之间不必有一对一的对应关系。只有当数据仅由可打印字符、控制字符水平制表符合换行符组成,紧靠换行符前面没有空格,并且最后一个字符是换行符时,从文本流中读出的数据才有必要和前面写入到该流中的数据一致。换行符正前面的空格在读取的时候是否出现是由实现定义的。
二进制流
二进制流是字符的有序序列,它可以透明地记录内部数据。在相同的实现下,从一个二进制流读入的数据应该和之前写入到这个流的数据相同。然而,这样的流可能会有一定数目的空字符附加在流的结束处,具体数目有实现定义。
环境限制
实现支持的文本文件的每一行应该至少可以包含254个字符,包括结束的换行符。宏 BUFSIZ 的值至少应该为256 。

1.3、 文件

打开文件
一个流通过打开一个文件来关联一个外部文件(也可以是一个物理设备),也可能涉及打开一个新的文件。创建一个现有的文件会丢弃这个文件以前的内容。如果文件支持定位要求(例如一个磁盘文件,和终端相对),那么和流相关的文件定位符就定位在文件的起始位置(零号字符处),除非文件用附加模式打开,这种模式下定位符的初始化在文件的起始位置还是结束位置是由实现定义的。文件定位符通过后来的读、写和定位要求得到维护,这样有助于文件的顺序行进。所有的输入都像是通过对函数 fgetc 的连续调用来读取,所有的输出都像是通过对函数
fputc 的连续调用来写入。
对一个文本流进行写操作是否会导致相关文件中超出操作点的内容被删除是由实现定义的。

缓冲文件
当一个流无缓冲时,字符很快从字符源或者在目标设备处出现。否则,字符就会累积然后作为一个块被传送到宿主环境或从宿主环境移出。当流为完全缓冲且缓冲区被填满时,字符就会作为一个块传送到宿主环境或者从宿主环境中移出。当一个流是行缓冲时,遇到换行符时字符就会作为一个块传送到或者移出宿主环境。而且,当缓冲器被填满时,且当请求对无缓冲的流输入或者当请求对需要从宿主环境传递字符的行缓冲的流输入时,字符就要作为一个块传送到宿主环境中。对这些属性的支持是由实现定义的,而且可能会受到函数 setbuf 和 setvbuf 的影响。
关闭文件
一个文件可以通过关闭文件来和控制流分开。输出流在流和文件分离之前被清空(任何没有写出的缓冲内容都被传送到宿主环境)。在相关的文件关闭之后(包括标准文本流),指向 FILE 对象的指针的值是不确定的。长度为零的文件(输出流没有向这个文件写入任何内容)是否存在是由实现定义的。
再次打开文件
文件以后可以被再次打开,被同一个或者另一个程序打开均可,它的内容也可以被使用和修改(如果能重新定位到它的起始位置的话)。如果main 函数返回它的原始调用者,或者调用了 exit 函数,那么在程序结束之前所有打开的文件就都关闭了(因此所有的输出流都被清空了)。
程序终止的其他方法,例如调用abort 函数,就不需要正确关闭所有的文件。
用来控制流的 FILE 对象的地址可能会很重要。不必使用 FILE 对象的副本来代替原始的对象进行服务。
程序开始执行时已经预定义了 3 个文本流,它们不需要显示打开——标准输入(读入常规的输入)、标准输出(写出常规的输出)和标准错误(写出诊断信息)。标准错误流打开的时候没有被完全缓冲;当且仅当流不会涉及交互设备时,标准输入和输出流才被完全地缓冲。
打开其他文件(非临时的)的函数需要一个文件名,这个名字是一个串。构成有效的文件名的规则是由实现定义的。同一个文件能否被同时打开多次也是由实现定义的。
环境限制
宏 FOPEN_MAX 的值至少是8 ,包括 3 个标准文本流。

1.4、 对文件的操作

1.4.1、函数 remove

概述:
#include <stdio.h>
int remove(const char * filename);
说明:
函数 remove 会导致一个文件再也不能通过它的文件名进行访问,这个文件的文件名是由 filename 指向的串。后面通过该文件名来打开这个文件的尝试就会失败,除非它被重新创建。如果要删除的文件已经打开了,remove 函数的行为是由实现定义的。
返回值:
函数 remove 在操作成功的时候返回零,否则返回非零。

1.4.2、函数 rename

概述:
#include <stdio.h>
int rename (const char *old , const char *new);
说明:
函数 rename 把名字为 old 指向的串的文件改名为 new 指向的串 ,这个文件再也不能通过以前的名字进行访问。如果调用函数之前存在一个名为 new 指向的串的文件,函数的行为是由实现定义的。
返回值:
如果操作成功,函数 rename 返回零; 失败,则返回非零。在新名字的文件存在的情况下,这个文件的名字仍然是原始的名字。

1.4.3、函数 tmpfile

概述:
#include <stdio.h>
FILE *tmpfile(void)
说明:
函数 tmpfile 创建一个临时的二进制文件,当这个文件关闭或者程序终止的时候它会被自动地移除。如果程序异常终止,打开的临时文件是否被移除是由实现定义的。这个文件打开时通过模式 “wb+” 进行更新。
返回值:
函数 tmpfile 返回一个指向它创建的文件流的指针。如果不能创建文件,函数返回一个空指针。

1.4.4、函数 tmpnam

概述:
#include <stdio.h>
char *tmpnam(char *s);
说明:
函数 tmpnam 生成一个字符,这个字符是一个有效的文件名,并且它不和现有的文件名相同。
每调用函数 tmpnam 一次,它就生成一个不同的名字 ,最多可以调用 TMP_MAX 次。如果调用的次数超过了 TMP_MAX 次,函数行为是由实现定义的。
实现应假设库函数没有调用函数 tmpnam 。
返回值:
如果参数是一个空指针,函数 tmpnam 把它的结果保留在一个内部静态对象中,并返回指向该对象的指针。对 tmpnam 函数的后续调用可能会修改该对象。如果参数不是一个空指针,就认为它指向一个至少有 L_tmpnam 个字符元素的数组,函数 tmpnam 把结果写到该数组中并返回参数值。
环境限制:
宏 TMP_MAX 的值至少为25 。

1.5、文件访问函数

1.5.1、函数 fclose

概述:
#include <stdio.h>
int fclose(FILE *stream);
说明:
函数 fclose 使 stream 指向的流被清空,并且和流相关联的文件被关闭。这个流中任何未写出的缓冲数据都传递到宿主环境中,然后写入文件中;任何未读出的缓冲数据都被丢弃。流和文件之间的关联也被解除。如果相关的缓冲是自动分配的,就把它释放。
返回值:
如果流被成功关闭,函数 fclose 返回零; 如果检测到任何错误,就返回EOF 。

1.5.2、函数 fflush

概述:
#include <stdio.h>
int fflush(FILE *stream);
说明: 如果 stream 指向一个输出流或者修改流,在这个流中,最近的操作不是输入,函数 fflush 会导致这个流所有未写入的数据传递给宿主环境,然后写入文件; 否则,函数的行为是未定义的。
如果 stream 是空指针,函数 fflush 对所有的流执行上述定义的清空行为。
返回值:
如果发生写入错误,函数 fflush 返回 EOF ; 否则,返回零。

1.5.3、函数 fopen

概述:
#include <stdio.h>
FILE *fopen(const char *filename , const char *mode)
说明:
函数 fopen 打开名字为 filename 指向的串的文件,并把这个文件和一个流相关联。参数 mode 指向以下面列出的字符开头的字符串。
r 打开现有文本文件以便读取。
w 生成新文本文件或截短现有文本文件至零长度以便写入。
a 附加。生成新文本文件或打开现有文本文件以便在文件结束处写入。
rb 打开现有二进制文件以便读取。
wb 生成新二进制文件或将现有二进截至零长度以便写入。
ab 附加。生成新二进制文件或打开现有二进制文件以便在文件结束处写入。
r+ 打开现有文本文件,以便更新(读和写)。
w+ 生成新文本文件或将现有文件截至零长度以便更新。
a+ 附加。生成新文本文件或打开现有文件以便更新,在文件结束处写入。
r+b或rb+ 打开现有二进制文件以便更新(读和写)。
w+b或wb+ 生成新二进制文件或截短现有文件至零长度以便更新。
a+b或ab+ 附加。生成新二进制文件或截短现有文件至零长度以便更新,在文件结束处写入。
用读模式 ( ’ r ’ 作为 mode 参数的第一个字符)打开一个文件时,如果文件不存在或者不能读,操作就会失败。
用附加模式 ( ’ a ’ 作为mode 参数的第一个字符)打开一个文件会使后面所有对文件的写操作都强制到当前的文件结束处,不管中间是否调用了函数 fseek 。在某些实现下,用附加模式(’ b ’ 作为以上mode 参数值列表的第二个或者第三个参数)打开一个二进制文件可能会把流文件定位符放置到超过写入的最后一个数据的地方,因为存在空字符填充。
当一个文件用更新模式(’ + ’ 作为以上mode 参数列表的第二个或者第三个字符) 打开时,对相关的流可以执行输入和输出操作。然而,如果中间没有调用函数 fflush 或者 文件定位函数 ( fseek 、fsetpos 、或者 rewind) , 输出可能不会直接跟在输入后面;如果中间没有调用文件定位函数,输入也可能不会直接跟在输出后面,除非输入操作恰好发生在文件结束处。在某些实现下,用更新模式打开(或者创建) 一个文本文件可能会代替打开(或者创建)一个二进制流。
当一个流打开时,当且仅当可以确定这个流不会涉及一个交互设备时,它才可以完成缓冲。该流的错误指示符和文件结束符会被清除。
返回值:
函数 fopen 返回指向控制流的对象的指针。如果打开操作失败,fopen返回空指针。

1.5.4、函数 freopen

概述:
#include <stdio.h>
FILE *freopen (const char *filename , const char *mode , FILE *stream);
说明:
函数 freopen 打开名字为 filename 指向的串的文件,并且把它和stream指向的流关联在一起。对mode 参数的使用与函数 fopen 中的相同。
函数freopen 首先尝试关闭和指定的流关联的任意文件。如果不能成功关闭,就忽略这一点。然后清空流的错误指示符和文件结束符。
返回值:
如果打开文件操作失败,函数 freopen 就返回一个空指针;否则 freopen 返回 stream 的值。

1.5.5、函数 setbuf

概述:
#include <stdio.h>
void setbuf (FILE *stream , char *buf);
说明:
除了没有返回值之外,函数 setbuf 就等价于函数 setvbuf , 而该函数是以参数 mode 为 _IOFBF 的值和参数size 为BUFSIZ的值被调用的,或者(如果 buf 是一个空指针) 是以参数mode 为 _IONBF 的值被调用的。
返回值:
函数 setbuf 没有返回值。

1.5.6、函数 setvbuf

概述:
#include <stdio.h>
int setvbuf( FILE *stream , char *buf , int mode , size_t size );
说明:
函数 setvbuf 只能在stream 指向的流和一个打开文件相关联之后,并且还没有对流执行任何其他操作之前使用。参数 mode 决定 stream 缓冲的方式,具体如下: _IOFBF 导致输入/输出完全缓冲;_IOLBF 导致输入/输出行缓冲;_IONBF导致输入/输出不缓冲。
如果 buf 不是一个空指针,可以使用它指向的数组来代替 setvbuf 函数分配的缓冲区,size 指定了数组的大小,数组的内容在任何时候都是不确定的。
返回值:
函数 setvbuf 成功时返回零,如果赋予参数mode 一个无效的值或者请求没有被响应,就返回非零。

1.6、格式化的输入输出函数

1.6.1、 函数 fprintf

概述:
#include <stdio.h>
int fprintf(FILE *stream , const char *format , …);
说明:
函数 fprintf 在 format 指向的串的控制下把输出写入stream 指向的流,format 指向的串指定了输出时转换的后续参数的格式。如果格式的参数不够,那么这种行为未定义。如果格式用完了而参数有剩余,那么(通常)也处理多余的参数;否则,就忽略它们。当遇到格式串的结尾时,函数fprintf返回。
格式应该是一个多字节符序列,以它的初始的转移状态开始和结束。格式由一条或者多条指示组成:普通的多字节字符(%除外),它们原封不动地被复制到输出流;转换说明,每个转换说明都会产生零个或者多个后续的参数。它以 %开头,%后面依次出现以下元素:

  • 零个或者多个标志字符(以任意顺序),修改转换说明的含义。
  • 可选最小字段宽度。如果转换值的宽度比字段宽度小,那么就在字段的左边(如果给定了左调整标志,或者右边,下面会描述)填充空格(默认)。字段宽度是一个星号的形式或者是一个十进制整数。
  • 可选的精度说明,它给出了 d、i、o、u、x、和X转换中出现的数字的最少个数;e、E与 f 转换的小数点右边的位数;g 与 G 转换的最大有效位数;s 转换中要从字符串写入的最大字符数。精度说明的形式是小数点后面跟一个星号或者一个可选的十进制整数。只有指定了句点的时候,采用的精度才是零。如果精度以其他转换说明符的形式出现,则这种行为未定义。
  • 可选的字母h用于转换操作d、i、o、x、或X,表示转换参数的类型为short int 或者 unsigned short int 。(参数可能根据整值提升规则进行了提升,它的值在打印之前应该转换为 short int 或者 unsigned short int 。) 字符 h 用于n转换时,表示转换参数的类型是 short int ※(星号)。一个可选的字母 l 用于转换操作d、i、o、u、x 与 X 时,表示转换参数类型为 long int ※(星号)。可选的字母L用于转换操作e、E、f、或 g 与 G ,表示转换参数的类型为 long double 。如果h、l或者L 跟其他的转换说明符一起出现,则这种行为未定义。
  • 指定要使用的转换类型的字符。像上面说明的那样,最小字段宽度或者精度,或者它们两个可以简化为一个星号。这种情况下,一个 int 参数提供了字段宽度或者精度。指定字段宽度或者精度或者它们两个的参数,应该顺序出现在所有要转换的参数之前。负的字段宽参数表示为 “-” 标志后面跟一个正的字段宽度。负的精度参数被当作没有精度说明对待。
    标志字符和它们的意思如下。
    “-” 左对齐字段宽度中的值。(如果没有使用这个标志字符,则是右对齐。)
    “+” 带符号转换的结果总是以一个+或-符号开始。(没有指定这个标志时,只有负值被转换时前面才带符号。)
    “空格” 如果一个带符号转换的结果中第一个字符不是符号或者转换的结果没有任何字符,就在结果前加一个空格。如果同时出现了空格 + 标志,空格标志将被忽略。
    “#” 如果有#标志,结果被转换为一个 “替换形式”。对o转换,它提高结果的精度来使结果的第一个数字为零。对 x 或者X 转换,一个非零结果的前缀是 0x 或者 0X 。对 e、E、f、g和G转换,即使小数点后面没有数,结果也要包含一个小数点。对g 和G转换来说,尾部的零不从结果中删除。对其他的转换使用#标志,则行为是未定义的。
    转换说明符和它们的含义如下。
    d、i int 参数转换为带符号的十进制数,形式为[-]dddd。精度指定了显示数字的最小数目,如果转换的值可以用更少的数字表示,则前面用零填充。默认的精度是l 。把零值用精度零转换,结果没有任何字符。
    o、u、x、X unsigned int 参数转换成无符号八进制数(o)、无符号十进制(u)或者无符号十六进制数(x或者X),形式为dddd 。x 转换使用字母 abcdef ,X转换使用字母ABCDEF 。精度指定了显示数字的最小数目,如果转换的值可以用更少的数字表示,则前面用零填充。默认精度是l 。把零值用精度零转换,结果没有任何字符。
    f double 参数转换为十进制,形式为 [-]ddd.ddd ,这里小数点字符后面的位数和精度说明符相等。如果不说明精度,则默认为6。如果精度为零并且没有使用# 标志,则不会出现小数点字符。 如果出现了一个小数点,则它的前面至少有一个数字。结果值为舍入到适当位数的数字。
    e、E double 参数转换为十进制,形式为[-]d.ddde±dd,这里,小数点前面至少要有一个数字(如果参数非零,这个数字也非零),小数点后面的位数和精度相等。如果不说明精度,则默认为6。如果精度为零并且没有使用 # 标志,则不会出现小数点字符。结果值为舍入到适当位数的数字。E转换说明符用 E 产生一个数来代替产生指数的e 。指数通常至少包含两位。如果值为零,指数就是零。

g、G double 参数转换为 f 或 e (对G转换来说是E)相同的样式,只不过精度指定的是有效数字的数组。如果精度是0,就把它当作1 。使用的样式由转换的值决定,只有转换产生的结果的指数小于-4或者不小于精度的时候才使用e(或者E)样式。删除结果小数部分尾部的零,只有小数点后面有数字的时候才显示小数点。

c int参数转换为unsigned char 类型,并且写出结果。
s 参数应该是指向字符类型数组的指针。写出字符数组中结束的空字符之前的所有字符,如果指定了精度,则最多写出精度数目的字符。如果没有指定精度或者精度比数组的元素个数大,那么数组应该包含一个空字符。
p 参数应该是指向void 的指针。参数的值按照实现定义的方式转换成一个可打印字符的序列。
n 参数是一个指向整型变量的指针,这个整型变量记录了到目前为止通过调用fprintf 所写到输出流的字符总数。不转换参数。
% 写出一个% ,不转换参数。完整的转换说明是 %% 。
如果一个转换说明是无效的,则行为是未定义的。
如果一个参数是,或者指向一个联合或者一个集合(除了使用 %s 转换的字符数组,或者使用%p 转换的指针),则行为是未定义的。
任何情况下,一个不存在的字段宽度或者很小的字段宽度都不会导致字段的截短。如果转换结果比字段宽度长,那么就扩展字段来包含转换结果。
返回值:
函数 fprinff 返回传送的字符数目,如果发生了输出错误,就返回一个负值。
环境限制
一次转换产生的字符的最大数目最少应该是509 。

1.6.2、 函数 fscanf

概述:
#include <stdio.h>
int fscanf(FILE *stream , const char *format , . . . );
说明:
函数 fscanf 在 format 指向的串的控制下 ,使用后面的参数作为指向接收转换后的输入的对象的指针。从 stream 指向的流中读取输入。
format 指向的串指定了可接受的输入序列和对它们进行转换以便赋值的方式。如果格式的参数不够,则行为是未定义的。如果格式用完了而参数有剩余,那么(通常)也处理多余的参数;否则,忽略它们。
格式应该是一个多字节字符序列,以它的初始化的转移状态开始和结束。格式由零个或者多个指示性语句组成:一个或者多个空白字符,一个普通的多字节字符(不是 % 和 空白字符),或者一个转换说明。
每一个转换说明都由字符 % 引入,在%后面按顺序出现下面的元素。

  • 可选的赋值取消字符 ※ 。
  • 可选的非零十进制整数,用来指定最大的字段宽度。
  • 可选字符h、l(ell)或者L ,用来说明接受对象的大小。如果一个参数是指向 short int 而不是int 的指针,则h 应该写在相应的转换说明符 d、i 和 n 之前;或者如果是指向long int 的指针 , 则 l 写在之前。同理,如果参数是指向 unsigned short int 而不是unsigned int 的指针,则 h 应该写在转换说明符 o、u和x之前;或者如果是unsigned long int ,则 l 写在之前。最后,如果参数是指向 double 而不是float 的指针,则 l应该写在转换说明符 e、f 和 g 之前;或者如果是long double , 则 L 写在之前。如果 h、l 或者 L 和其他转换说明符出现在一起,则行为是未定义的。
  • 一个字符,这个字符指定了待用的转换类型。下面会说明有效的转换说明符。
    函数 fscanf 依次执行格式中的每条指示。如果一个指示失败了,就像下面描述的细节那样,函数 fscnaf 依次执行格式中的每条指示。如果一个指示失败了,就像下面描述的细节那样,函数 fscanf 就返回。失败是指输入失败(因为一个不可用的输入字符)或者匹配失败(因为不适当的输入)。
    由任意个空字符组成的指示通过读取输入来执行,直到遇到第一个非空白字符(不对它进行读取),或者直到再也没有字符可以读取。
    一个普通的多字节字符指示读取流的下一个字符。如果一个字符和组成控制语句的字符不同,则指示失败,不同的字符和它后面的字符都不能被读取。
    一个转换说明符指示定义了匹配输入序列的一个集合,下面详细描述了每一个说明符。转换说明符按照以下的步骤执行:
    跳过输入的空白字符(由 isspace 函数指定),除非说明包含一个 [ 、c 或者n 说明符。从输入流中读取一个输入项,除非说明包含一个n 说明符。一个输入项是输入字符的最长的匹配序列,除非它超过了指定的字段宽度,这种情况下它是序列中前面的该长度个字符。如果输入项后面还有字符的话,后面的第一个字符仍然没有被读取。如果输入项的长度为零,则指示执行失败:这种情况是匹配失败,除非一个错误阻止从流的输入,这种情况是输入失败。
    除了一个 % 说明符的情况,输入项(或者在一个 %n 指示的情况下,输入字符的总数)被转换为和转换说明符适应的类型。如果输入项不是一个匹配的序列,指示的执行失败:这种情况是一个匹配失败。除非用一个 * 指示一个赋值取消,否则转换的结果存储在 format 后面的第一个参数指向的对象中,这个对象还没有接收到转换的结果。如果这个对象没有合适的类型,或者转换的结果不能在提供的空间中表示,则行为未定义。
    下面的转换说明符是有效的。
    d 和一个可选的有符号十进制整数相匹配,这个整数的格式和 strtol 函数 base 参数为 10 时的目标序列所期望的格式相同。相应的参数是一个指向整数的指针。

i 和一个可选的有符号整数相匹配,这个整数的格式与 strtol 函数 base 参数为 0 时的目标序列所期望的格式相同。相应的参数应该是一个指向整数的指针。

o 和一个可选的有符号八进制整数相匹配,这个整数的格式和strtoul 函数 base 参数为 8 时的目标序列所期望的格式相同。相应的参数应该是一个指向无符号整数的指针。

u 和一个可选的有符号十进制整数相匹配,这个整数的格式和 strtoul 函数 base 参数为 10 时的目标序列所期望的格式相同,相应的参数应该是一个指向无符号整数的指针。

x 和一个可选的有符号十六进制数相匹配,这个整数的格式和 strtoul 函数 base 的参数为 16 时的目标序列所期望的格式相同。相应的参数是一个指向无符号整数的指针。

e、f、g 和一个可选的有符号浮点数匹配,该浮点数格式和函数 strtod 的目标序列所期望的格式相同。相应的参数是一个指向浮点数的指针。

s 和一个非空白字符序列匹配。相应的参数应该是指向一个数组的首字符的指针,这个数组应足够大,可以接收该字符序列和一个结束的空字符,该字符会被自动添加。

[ 和一个非空字符 序列匹配,这些字符都属于一个字符集(扫描集)。相应的参数应该是指向数组的首字符的指针,这个数组应足够大,可以接收该序列和一个终止的空字符,该字符会被自动添加。转换说明符包括 format 串后面的所有字符,直到匹配的右括号(]) ,而且包括这个括号。两个括号之间的字符(扫描列表)组成了扫描集,除非左括号后面的字符是音调符号(^),这种情况下扫描集包含了音调符号和右括号之间所有不出现在扫描列表中的字符。如果转换说明符以[ ] 或者 [ ^ ]开头,那么右括号字符在扫描列表中,下一个右括号才是结束说明的匹配的右括号;否则,第一个右括号就是终止说明的右括号。如果 “-” 字符出现在扫描列表中,并且它不是第一个字符,也不是以 ^ 为第一个字符时的第二个字符,也不是最后一个字符,则行为是由实现定义的。

c 和一个字符序列匹配,字符的数目由字段宽度指定(如果指示中没有给出字段宽度,则数目为1)。相应的参数为指向一个数组的首字符的指针,这个数组足够大,可以接收这个序列,不会添加空字符。

p 和一个实现定义的序列集合相匹配,这个序列集合应该和函数 fprintf 使用 %p 转换生成的序列集合相同。相应的参数是一个指向void 的指针的指针。输入项的解释是由实现定义的。如果输入项是之前同一个程序执行过程中转换得到的一个值,那么产生的指针应该和这个值相等;否则,%p 转换的行为是未定义的。

n 不读取输入,相应的参数是指向一个整数的指针,这个整数记录了到目前为止通过调用 fscanf 函数从输入流读取的字符的总数。执行一个%n 指示不会增加 fscanf 函数执行完成时返回的赋值总数。

% 和一个 % 匹配,不进行转换或者赋值。完整的转换说明应该是 %%。

如果转换说明是无效的,则行为未定义。
转换说明符 E、G 和 x 也是有效的,它们的行为分别和 e、g 和 x 相同。
输入的时候如果遇到一个文件结束符(而不是允许出现开头的空白),则 当前指示因输入失败而终止执行;否则,除非当前指示以一个匹配失败终止执行,下一条指示 (如果有的话) 就因输入失败终止执行。
如果转换因为一个无法识别的输入字符而终止,那么这个输入字符留在输入流中不被读取。尾部的空白(包括换行符)也留在输入流中不被读取,除非它和一个指示匹配。和通过使用 %n指示相比,文字匹配和取消赋值的赋值取消标志的成功执行不能被直接确定。
返回值:
如果在任何转换之前发生了输入失败,函数 fscanf 返回宏 EOF 的值;否则,函数 fscanf 返回赋值的输入项的数目,这个值会比早期发生了匹配失败时提供的值小,甚至有可能为0 。

1.6.3、 函数 printf

概述:
#include <stdio.h>
int printf( const char *format , . . . );
说明:
函数printf 和 fprintf 等价,只不过 fprintf 把参数 stdout 插到了 printf 的参数的前面。

返回值:
函数 printf 返回传送的字符数,发生输出错误的时候,就返回一个负值。

1.6.4、 函数 scanf

概述:
#include <stdio.h>
int scanf(const char *format , . . . );
说明:
函数 scanf 和 fscanf 等价,只不过 fscanf 把参数 stdin 插到 scanf 的参数之前。
返回值:
如果在任何转换之前发生了输入失败,函数 scanf 返回宏 EOF 的值;否则,函数 scanf 返回赋值的输入项的数目,这个值可能比早期发生了匹配失败的情况提供的值小,或者甚至是零。

1.6.5、 函数 sprintf

概述:
#include <stdio.h>
int sprintf(char *s , const char *format , . . . );
说明:
函数 sprintf 等价于 fprintf ,只不过参数 s指定了一个数组,生成的输出写入到这个数组中,而不是写到一个流中。在写入的字符最后写入一个空字符,它不计入返回和的一部分。如果两个交迭的对象之间发生了复制,则行为未定义。
返回值:
函数 sprintf 返回写到数组中的字符的数目,不包括终止的空字符。

1.6.6、 函数 sscanf

概述:
#include <stdio.h>
int sscanf(const char *s ,const char *format , . . .);
说明:
函数sscanf 和 fscanf 等价,只不过参数 s 指定了一个串,输入是从这个串中获取,而不是从流中获取。到达串的结尾等价于函数 fscanf 遇到了文件结束符。如果两个交迭的对象之间发生了复制,则行为未定义。

返回值:
如果在任何转换之前发生了输入错误,函数 sscanf 返回宏 EOF 的值。否则,函数 sscanf 返回输入项赋值的数目,这个值可能比早期发生了匹配错误的情况提供的值小,甚至可能为零。

1.6.7、 函数 vfprintf

概述:
#include <stdarg.h>
#include <stdio.h>
int vfprintf (FILE *stream , const char *format ,va_list arg);
说明:
函数 vfprintf 等价与函数 fprintf ,只不过可变参数表用 arg 代替,它已经被宏 va_start(可能后来还有va_arg 调用) 初始化了。函数 vfprintf 不调用宏 va_end。
返回值:
函数 vfprintf 返回传送的字符数目,如果发生了输出错误,则返回一个负值。

1.6.8、 函数 vprintf

概述:
#include <stdarg.h>
#include <stdio.h>
int vprintf(const char *foramt , va_list arg);

说明:
函数 vprintf 等价于printf ,只不过用 arg 代替可变参数表,它已经被宏 va_start(可能后来还有 va_arg 调用)初始化了。函数 vprintf 不调用宏 va_end。
返回值:
函数vprintf 返回传送的字符数目,发生了输出错误的时候,返回一个负值。

1.6.9、 函数 vsprintf

概述:
#include <stdarg.h>
#include <stdio.h>
int vsprintf (char *s , const char *format , va_list arg);

说明:
函数 vsprintf 等价于 sprintf ,只不过可变参数表用arg 代替,它已经被宏va_start (可能后来还有va_arg调用) 初始化了。函数vsprintf 不调用宏 va_end。如果两个交迭的对象之间发生了复制,则行为未定义。
返回值:
函数 vsprintf 返回写入数组中的字符数目,不包括终止的空字符。

1.7、字符输入/输出函数

1.7.1、函数 fgetc

概述:

#include <stdio.h>
int fgetc(FILE *stream);
说明:
函数 fgetc从stream 指向的输入流中读取下一个字符(如果有的话),并把它由 unsigned char 类型转换为 int 类型,并且流的相关的文件定位符(如果定义的话)向前移动一位。
返回值:
函数 fgetc 返回stream 指向的输入流中的下一个字符。如果输入流在文件结束处,则设置文件结束符,函数fgetc 返回EOF。如果发生了读错误,则设置流的错误指示符,函数fgetc 返回 EOF 。

1.7.2、函数 fgets

概述:
#include <stdio.h>
char *fgets(char *s , int n, FILE *stream);
说明:
函数fgets 从stream 指向的流中读取字符,读取字符的数目最多比 n 指定的数目少1,然后将字符写入到s 指向的数组中。读入换行符(保留)或者文件结束之后,不再读取其他的字符。最后一个字符写入数组后立即写入一个空字符。
返回值:
如果成功执行,则函数fgets 返回s 。如果遇到文件结束并且没有向数组写入字符,则数组的内容不变且返回一个空指针。如果操作的过程中发生了读错误,则数组的内容不确定,并返回一个空指针。

1.7.3、函数 fputc

概述:
#include <stdio.h>
int fputc(int c , FILE *stream);
说明:
函数 fputc 把c 指定的字符 (转换为 unsigned char 类型) 写到 stream 指向的输出流中相关的文件定位符 (如果定义的话) 指定的位置处,并把文件定位符向前移动适当的位置。如果文件不支持定位要求或者流以附加模式打开,字符就添加到输出流的后面。
返回值:
函数 fputc 返回写入的字符。如果发生了写错误,则设置流的错误指示符,函数fputc 返回 EOF 。

1.7.4、函数 fputs

概述:
#include <stdio.h>
int fputs(const char *s , FILE *stream);
说明:
函数fputs 把 s 指向的串写入 stream 指向的流中 ,不写入结束的空字符。
返回值:
如果发生了写错误,则函数fputs 返回 EOF 。否则,它返回一个非负值。

1.7.5、函数 getc

概述:
#include <stdio.h>
int getc(FILE *stream);
说明:
函数getc 等价与函数fgetc ,只不过如果getc 作为一个宏实现,它可能会对stream 进行多次计算,所以它的参数不能是具有副作用的表达式。
返回值:
函数getc 返回stream 指向的输入流的下一个字符。如果流处于文件结束处,则设置该流的文件结束指示符,函数getc 返回 EOF 。如果发生了读错误,则设置流的错误指示符,函数getc 返回EOF 。

1.7.6、函数 getchar

概述:
#include <stdio.h>
int getchar(void);
说明:
函数 getchar 等价于参数 stdin 调用的函数getc 。
返回值:
函数 getchar 返回 stdin 指向的输入流的下一个字符。如果流处于文件结束处,则设置流的文件结束符,函数 getchar 返回EOF 。如果发生了读错误,则设置流的错误指示符,getchar 返回 EOF 。

1.7.7、函数 gets

概述:
#include <stdio.h>
char *get(char *s)
说明:

函数gets 从 stdin 指向的输入流中读取若干个字符,并将其保存到 s 指向的数组中,直到遇到文件结束或者读取一个换行符。所有的换行符都被丢弃,在最后一个字符读到数组中之后立即写入一个空字符。
返回值:
函数gets 成功执行时返回 s 。如果遇到了文件结束并且数组中没有读入任何字符,则数组的内容保持不变,返回一个空指针。如果操作的过程中发生了读错误,则数组的内容不确定,返回一个空指针 。

1.7.8、函数 putc

概述:
#include <stdio.h>
int putc(int c , FILE *stream);
说明:
函数 putc 等价于fputc ,只不过如果 putc 作为一个宏实现,它可能会对 stream 计算多次,所以它的参数不能是有副作用的表达式。
返回值:
函数 putc 返回写入的字符。如果发生了写错误,则设置流的错误指示符,putc 返回 EOF 。

1.7.9、函数 putchar

概述:
#include <stdio.h>
int putchar(int c);
说明:
函数 putchar 等价于把stdout 作为第二个参数调用的 putc 。
返回值:
函数 putchar 返回写入的字符。如果发生了写错误,则设置流的错误指示符, putchar 返回 EOF 。

1.7.10、函数 puts

概述:
#include <stdio.h>
int puts(const char *s);
说明:
函数puts 把 s 指向的串写到 stdout 指向的流中,并且在输出最后添加一个换行符。不写入结束的空字符。
返回值:
如果发生了写错误,函数puts 返回 EOF 。否则,它返回一个非负值。

1.7.11、函数ungetc

概述:
#include <stdio.h>
int ungetc (int c ,FILE *stream);
说明:
函数 ungetc 把 c 指定的字符(转换为 unsigned char 类型) 退回到 stream 指向的输入流中。退回字符是通过对流的后续读取并按照退回的反顺序来返回的。如果中间成功调用(对同一个流)了一个文件定位函数(fseek、fsetpos 或者 rewind),那么就会丢弃流的所有退回的字符。流的相应的外部存储保存不变。
退回的一个字符是受保护的。如果对同一个流调用 ungetc 函数太多次,中间又没有读或者文件定位操作,那么这种操作可能会失败。
如果 c 的值和宏 EOF 的值相等,则操作失败且输入流保持不变。
对ungetc的成功调用会清空流的文件结束符。读取或者丢弃所有回退的字符之后,流的文件定位符的值和这些字符回退之前的值相同。对文本流来说,在对函数ungetc的一次成功调用之后,它的文件定位符的值是不明确的,直到所有回退字符被读取或者丢弃为止。对二进制来说,每成功调用一次 ungetc 之后它的文件定位符都会减 1 。如果在一次调用之前它的值是零,那么调用之后它的值是不确定的。
返回值:
函数 ungetc 返回转换后的回退字符。如果操作失败,则返回 EOF。

1.8、直接输入/输出函数

1.8.1、函数 fread

概述:
#include <stdio.h>
size_t fread(void *ptr ,size_t size ,size_t nmemb ,FILE *stream);
说明:
函数 fread 从 stream 指向的流中读取最多 nmemb 个元素到 ptr 指向的数组中, nmemb 的大小是由size 指定的。流的文件定位符(如果定义的话) 根据成功读取的字符数向前移动。如果发生了错误,流的文件定位符最后的值是不确定的。如果只读取了部分元素,它的值也是不确定的。
返回值:
函数 fread 返回成功读取的元素的数目,如果发生了读错误或者遇到了文件结束,返回值可能比 nmemb 小。如果size 或者 nmemb 为零,则fread 返回零且数组的内容和流的状态保持不变。

1.8.2、函数 fwrite

概述:
#include <stdio.h>
size_t fwrite(const void *ptr , size_t size , size_t nmemb, FILE *stream);
说明:
函数 fwrite 从 ptr 指向的数组中读取最多 nmemb 个元素并将其写到 stream 指向的流中,nmemb 的大小是由size 指定的。流的文件定位符(如果定义的话)根据成功写入的字符数向前移动。如果发生了错误,流的文件定位符最后的值是不确定的。
返回值:
函数fwrite 返回成功写入的元素的数目。如果遇到了写错误,它可能比nmemb 小。

1.9、文件定位函数

1.9.1、函数 fgetpos

概述:
#include <stdio.h>
int fgetpos (FILE *stream , fpos_t *pos);
说明:
函数 fgetpos 把 stream 指向的流的文件定位符的当前值存储到 pos 指向的对象中。
存储的值包含了未指明的信息,函数 fsetpos 可以使用这些信息来使流重新定位到这次调用函数 fgetpos 时的位置。
返回值:
如果操作成功,函数 fgetpos 返回零;如果不成功,函数fgetpos 返回非零并且把一个由实现定义的正值存储在 errno 中。

1.9.2、函数 fseek

概述:
#include <stdio.h>
int fseek (FILE *stream , long int offset , int whence);
说明:
函数 fseek 为 stream 指向的流设置文件定位符。
对二进制流来说,新的位置从文件的开始以字符为单位进行测量,通过在whence 指定的位置上加上 offset 来获得。如果whence 是SEEK_SET,指定的位置就是文件的开始位置,如果是SEEK_CUR,就是文件的当前位置,如果是SEEK_END,则是文件的结束位置。
二进制流不需要严格支持whence 为 SEEK_END 时的fseek 调用。
对文本流来说,offset 或者是零,或者是前面对同一个流调用ftell 函数返回的值,whence 应该是SEEK_SET 。
对函数 fseek 的成功调用会清空流的文件结束符并且解除 ungetc 函数对这个流的任何影响。调用fseek 之后,对更新后的流的下一个操作可能是输入或者输出。
返回值:
只有当不能满足请求时,函数fseek 才返回非零值。

1.9.3、函数 fsetpos

概述:
#include <stdio.h>
int fsetpos(FILE *stream , const fpos_t *pos);
说明:
函数 fsetpos 根据pos 指向的对象的值来设置 stream 指向的流的文件定位符,pos 指向的对象的值应该是前面对同一个流调用函数 fgetpos 得到的返回值。
对函数 fsetpos 的成功调用会清空流的文件结束并且解除 ungetc 对这个流的影响。调用 fsetpos之后,对更新后的流的下一个操作可能是输入或输出。
返回值:
如果操作成功,函数fsetpos 返回零;如果不成功,函数fsetpos 返回非零并且把一个由实现定义的正值存储在 errno中。

1.9.4、函数 ftell

概述:
#include <stdio.h>
long int ftell(FILE *stream);
说明:
函数ftell 获得stream 指向的流的文件定位符的当前值。对一个二进制流来说,这个值是从文件开头到当前位置的字符的数目;对一个文本流来说,它的文件定位符包含了未说明的信息,函数fseek 可以使用这些信息来使流的文件定位符回到这次调用ftell时的位置。这两个返回值的差值不一定可以作为读取或者写入的字符数使用。
返回值:
如果成功执行,函数ftell 返回流的文件定位符的当前值。如果失败了,函数ftell 返回 -1L 并且把一个实现定义的正值存储在errno 中。

1.9.5、函数 rewind

概述:
#include <stdio.h>
void rewind(FILE *stream);
说明:
函数 rewind 把stream 指向的流的文件定位符设置在文件的开始位置,它等价于 (void) fseek(stream , 0L ,SEEK_SET)
只不过流的错误指示符也被清零。
返回值:
函数 rewind 没有返回值。

1.10、错误处理函数

1.10.1、函数 clearerr

概述:
#include <stdio.h>
void clearerr(FILE *stream);
说明:
函数 clearerr 清空 stream 指向的流的文件结束符和错误指示符。
返回值:
函数 clearerr 没有返回值。

1.10.2、函数 feof

概述:
#include <stdio.h>
int feof(FILE *stream);
说明:
函数 feof 测试 stream 指向的流的文件结束符。
返回值:
当且仅当 stream 流设置了文件结束符时 feof返回一个非零值。

1.10.3、函数 ferror

概述:
#include <stdio.h>
int ferror(FILE *stream);
说明:
函数 ferror 测试 stream 指向的流的错误指示符。
返回值:
当且仅当stream 流设置了错误指示符时函数ferror 返回非零。

1.10.4、函数 perror

概述:
#include <stdio.h>
void perror(const char *s);
说明:
函数perror 把整数表达式 errno 中的错误编号转换为一条错误信息。它把一个字符序列写到一个这样的标准错误流:首先(如果s不是空指针并且s指向的字符不是空字符),s指向的串后面跟一个冒号(:)和一个空格;然后是一个适当的错误信息串后面跟一个换行符。错误信息串的内容和用参数error 调用函数 strerror 的返回值相同,这是由实现定义的。
返回值:
函数perror 没有返回值。

二、总结

实际上,标准C要求流执行I/O是向后退了一步。现在每一个程序都要在用户存储区存放一个复杂的控制块以记录每一个流的状态。分配和释放控制块(FILE 数据对象)的时候一定要小心。不能直接对控制块和它控制的缓冲进行读取或写入。必须按照某种顺序调用函数来执行流的I/O操作。

相关文章:

  • 【GIS】高分辨率遥感影像智能解译
  • 【Leetcode每日一题】34.在排序数组中查找元素的第一个和最后一个位置|二分求下标
  • 分支语句与循环语句
  • 【Python语言基础】——Python 类和对象
  • Java基础 Stream流方法引用异常文件
  • 【Hadoop】HDFS+Shell实践(定时上传数据至HDFS)
  • 约数个数及约数之和知识点(含公式)
  • 仿牛客论坛项目
  • Linux——进程间通信
  • 《深入浅出计算机组成原理》学习笔记 Day9
  • 2023年新年烟花代码(背景音乐完整版)
  • STM32编写OLED显示屏驱动
  • 【操作系统】—— Windows常用快捷键(带你快速了解)
  • 【数据结构之二叉树系列】二叉树的基本知识
  • 04 |「链表」简析
  • Spring笔记上(基于XML配置)
  • 十六进制转八进制+超大数据处理(蓝桥杯基础练习C/C++)
  • 线性代数[向量]
  • 请求体类型全解
  • Linux嵌入式开发——文件系统结构
  • https://app.hackthebox.com/machines/Inject
  • Spring —— Spring简单的读取和存储对象 Ⅱ
  • 渗透测试之冰蝎实战
  • Mybatis、TKMybatis对比
  • Microsoft Office 2019(2022年10月批量许可版)图文教程
  • 《谷粒商城基础篇》分布式基础环境搭建
  • 哈希表题目:砖墙
  • Vue 3.0 选项 生命周期钩子
  • 【车载嵌入式开发】AutoSar架构入门介绍篇
  • 【计算机视觉 | 目标检测】DETR风格的目标检测框架解读