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

搜索推广网站哪家做的最好凡科网做网站能达到什么效果

搜索推广网站哪家做的最好,凡科网做网站能达到什么效果,短链接生成,如何做网站在售产品分析前言#xff1a;Hello#xff0c;大家好#x1f618;#xff0c;我是心跳sy#xff0c;上一节我们主要学习了格式化输入输出的基本内容#xff0c;这一节我们对格式化进行更加深入的了解#xff0c;对文件概念进行介绍#xff0c;并且对输入、输出与文件读写的基本概念… 前言Hello大家好我是心跳sy上一节我们主要学习了格式化输入输出的基本内容这一节我们对格式化进行更加深入的了解对文件概念进行介绍并且对输入、输出与文件读写的基本概念进行学习本节主要对printf,scanf深入了解并介绍文件处理函数如fprintffopenfclosefreopentmpfiletmpnamfflushsetvbufsetbuf以及其他文件操作函数进行理解对字符的输入输出putchar,getchar,fputc,fgetc行的输入输出puts,fputs,gets,fgets块的输入输出fread,fwrite以及字符串的输入和输出sprintf,snprintf,sscanf会到下一节介绍我们一起来看看吧 c语言的输入/输出库非常庞大并且是c语言的高级应用我们前面已经学会使用printf,scanf函数的基本用法这一节我们主要对文件操作进行介绍并对格式化输入输出函数进行深入的了解上一节还没太懂的友友们看完这一篇相信会有更加深入的了解~  我们知道文件读写是许多应用程序不可缺少的部分在计算机编程中起着至关重要的部分它允许程序通过读入和写入文件来持续化数据以此来实现数据的长期保存和共享而文件读写的基本概念是通过输入输出操作来与计算机上的文件进行交互所以我们需要熟练掌握运用❗️❗️ 本篇文章对各个示例均有详细的解释对难理解的概念也进行了详细的诠释耗时几天完成内容较长精心打造无cv概念均参考权威书籍。友友们耐心看完放心食用没学过文件和有关输入输出的友友们也能看懂哦~ 1、⭐️流的概念⭐️ 在c语言中流表示任意输入的源或任意输出的目的地可以想象成水流只不过c语言的流更富有逻辑顺序概念它提供和储存数据产生数据的叫做输入流消耗数据的叫做输出流c程序与数据的交互都是以流的形式进行的而我们下来介绍的文件读写就是先“打开文件”以打开数据流然后“关闭文件”以关闭数据流我们之前学习的printf,scanf就是格式化的输出函数、输入函数所属的流是标准流我们接下来会详细介绍~ 1.1、文件指针  一般形式FILE *指针变量标识符c程序中对流的访问是通过文件指针实现的文件指针的类型是FILE *FILE类型在头stdio.h中声明其中文件指针表示的特定流具有标准的名字比如stdin指针标准输入流等如果用户需要也可以自定义流FILE *fp注意操作系统通常会限制可以同时打开的流但程序可以声明任意数量的FILE *类型变量。 1.2、标准流和重定向  c语言头stdio.h提供了3个标准流同样c中头iostrream也提供了标准输入输出流,我们以后介绍c语言中这3个标准流可以直接使用不需要对其进行声明也不用打开或关闭它们。下图提供3个标准流 这3个标准流的应用非常广泛我们经常使用的printf,scanf,putchar,getchar,puts,gets函数都是通过stdin获得输入通过stdout进行输出的。默认情况下stdin表示键盘stdout和stderr表示屏幕然而许多操作系统允许通过重定向的机制来改变这些默认的含义。  通常我们可以强制程序从其他文件获得输入而不是从键盘那里方法是在命令行中放上文件的名字并在其前面加上字符小于号跟在程序名后面:这里demo是指程序意为demo程序代码里面的stdin将指向文件in.dat即从in.dat中获取数据 demoin.dat ⭕️这种方法叫做输入重定向它的本质是使stdin流表示文件in.dat而非键盘其精妙之处在于demo程序不会意识到在从文件in.dat中读取数据它会认为从stdin获得的任何数据都是从键盘输入的。 ⭕️输出重定向与输入重定向类似对stdout流的重定向是通过在命令行中放置文件名并在其前加上字符大于号实现 demoout.dat 现在所有写入stdout流的数据都将进入out,dat文件中而不是出现在屏幕上。值得一提的是我们还可以把输入重定向和输出重定向结合起来使用而且,字符不用与文件名相邻重定向文件的顺序也无关紧要下面两个例子是等效的 demo in.dat out.dat demo out.dat in.dat ⚠️需要注意的是输出重定向有一个问题就是会把写入stdout的所有内容都放入文件中如果程序运行失常或写出出错消息那么我们在看文件的时候才能发现而这些应该是出现在stderr中的所以通过把出错消息写到stderr而不是stdout中可以保证即使在对stdout重定向时出错消息仍能显示到屏幕上。比如linux c语言用perror函数将错误消息写入标准错误stderr 1.3、文本文件与二进制文件 stdio.h支持两种类型的文件文本文件和二进制文件。我们知道计算机的储存在物理上是二进制的所以文本文件与二进制文件的区别不是物理上的而是逻辑上的两者只在编码层次上有差异简单的来说文本文件是基于字符编码的文件人们可以检查和编辑文件常见的编码有ASCII编码、UNICODE编码等等例如c程序的源代码是储存在文本文件中二进制文件是基于值编码的文件其中字节除了可以表示字符还可以表示其他类型的数据比如浮点数和整数。 如果上面概念还未完全理解我们再次深入理解 文本文件基于字符编码基本上是定长编码也有非定长如UTF-8,每个字符在具体编码中是固定的如ASCII码是8个比特的编码UNICODE一般占16个比特。而二进制文件可看成是变长编码因为是值编码多少比特代表一个值完全由自己决定所以比较灵活节约空间。 我们来看一个栗子当存储实型数字时如3.1415927文本文件需要9个字节分别存储3 . 1 4 1 5 9 2 7这9个字符的ASCII值而二进制文件只需要4个字节DB 0F 49 40 我们经常会遇到用记事本打开文件乱码的情况原因如何❓  文本工具打开一个文件首先读取文件物理上所对应的二进制比特流然后按照所选择的解码方式来解释这个流然后将这个解释结果显示出来。一般来说选取的解码方式会是ASCII码形式一个字符8个比特接下来它会8个比特8个比特地来解释文件流记事本无论打开什么文件都按既定的字符编码工作ASCII码所以当打开一个二进制文件时就会出现乱码因为解码和译码不对应。 ⚠️文本文件具有两种二进制文件没有的特性 ⭕️1、文本文件分为若干行。文本文件的每一行通常以一两个特殊字符结尾特殊字符的选择与操作系统有关。在Windows中行末的标记是回车符\x0d与一个紧跟其后的回行符\x0a。在UNIX和Macintosh操作系统Mac OS新版中行末的标记是一个单独的回行符。 \x0d代表回车字符它的ASCII码值为13十进制。在文本文件中回车字符通常用于表示光标返回到当前行的开头但不换行。\x0a代表换行字符它的ASCII码值为10十进制。换行字符用于在文本文件中表示将光标移动到下一行的开头。 在不同的操作系统和编程环境中回车和换行字符的使用方式可能会有所不同 在Windows操作系统中通常使用回车和换行两个字符\r\n来表示换行即先回车再换行。\r的ASCII码就是13是回车\n的ASCII码为10,是换行与\x0a,\x0d等价在Unix/Linux操作系统和类Unix环境如macOS中通常只使用换行字符\n来表示换行。在早期的Macintosh操作系统中通常只使用回车字符\r来表示换行。 ⭕️2、文本文件可以包含一个特殊的“文件末尾”标记。一些操作系统允许在文本文件的末尾使用一个特殊的字节作为标记。在Windows中标记为\xlaCtrlZ。CtrlZ不是必须的但如果存在它就标志着文件的结束其后的所有字节都会被忽略。使用CtrlZ的这一习惯继承自DOS磁盘操作系统而DOS中的这一习惯又是从CP/M早期用于个人计算机的一种操作系统来的。大多数其他操作系统包括UNIX没有专门的文件末尾字符。 ⭕️二进制文件不分行也没有行末标记和文件末尾标记所有字节都是平等对待的。 2、⭐️文件操作⭐️ 输入输出重定向虽然简单易懂但是在许多程序中受限制当程序依赖重定向时它无法控制自己的文件甚至无法知道这些文件的名字也无法同时写入或读入两个文件所以这时我们将使用stdio.h提供的文件操作我们下面一起来学习打开、关闭文件、改变缓冲文件的方式以及怎样删除文件和重命名文件 2.1、打开文件fopen函数 如果要把文件用作流打开时就需要调用fopen函数也叫作打开文件流。fopen的第一个参数是含有要打开文件名的字符串其值应符合运行环境的文件名规范可以包含路径位置信息(如果系统支持)。第二个参数是“模式字符串”它用来指定打算对文件执行的操作例如字符串“r”表示从文件读入数据但不会向文件写入数据我们下面会详细介绍。  ⚠️注意从C99开始对fopen函数原型声明用restrict关键字进行修饰这表明filename和mode所指向的字符串的内存单元不共享。 ⚠️⚠️⚠️注意在Windows系统中fopen函数调用用的文件名中含有字符 \ 时一定要小心c语言会把 \ 看作转义字符的开始标志。如下图 fopen(c:\test_8_9\test1.dat, r) 以上调用会失败因为编译器会把 \t 看作转义字符所以有效的办法是用 \\ 来代替 \ 或者直接使用 / 代替 \ 。如下两种方法都可行 fopen(c:\\test_8_9\\test1.dat, r) fopen(c:/test_8_9/test1.dat, r) fopen函数返回一个文件指针程序通常把此指针存储在一个变量中然后后续使用时直接使用fopen函数常见调用形式如下其中fp是FILE*类型的变量当程序调用输入函数从文件in.dat中读取数据时会把fp作为实参。 当无法打开文件时fopen函数会返回一个空指针其原因可能是因为文件位置不对或者我们没有打开文件的权限。 fp fopen(in.dat, r); 我们看下面的一个例子下面的例子fopen函数的一个参数是文件路径第二个参数模式字符串中采用了“w”意为打开文件“写” #includestdio.h int main() {FILE* fp fopen(C:\\Users\\樊双艺\\Desktop\\c.txt.txt, w);if (fp ! NULL){fprintf(fp, Hello, world!\n);fclose(fp);}return 0; } 我们可以看到文本文件中写入了Hello,world! ⚠️⚠️⚠️这个例子有几点需要大家注意 ⭕️永远不要假设可以打开文件每次都要测试 fopen函数的返回值以确保不是空指针所以这里我们用 if语句来判断 fp是否为空这里的 fprintf函数稍后介绍我们现在只需要知道它的第一个参数是指向要写入文件的指针。 ⭕️当成功写入文件后我们需要关闭文件一定要注意这是配套存在的❗️❗️❗️ 2.2、模式 fopen函数的第二个参数要传递哪种模式字符串不仅依赖于稍后我们想对文件进行什么操作还取决于文件中的数据是文本形式还是二进制形式。 下图为文本文件的模式字符串  下图为二进制文件的模式字符串当使用fopen打开二进制文件时需要在模式字符串包含字母bUNIX系统中文本文件与二进制文件具有完全相同的格式所以不需要字母b但是UNIX程序员仍应该包含字母b便于代码移植 ⭕️从两个表格可以看出头stdio.h对写数据和追加数据进行了区分当给文件写数据时通常会对先前的内容进行覆盖然而当为追加文件时向文件写入的数据添加在文件末尾因而可以保留文件的原始内容。  ⭕️另外带有字母“x”的打开模式是从C11才开始引入的这个字母表示独占模式。在这种模式下如果文件已经存在或者无法创建fopen函数将执行失败否则文件将以独占非共享模式打开。 ⭕️图中带有“”的字符串也就是当打开文件用于读和写时需要先调用一个文件定位函数不然就不能从读转为写除非读遇到文件末尾相应的如果既没调用fflush函数也没有文件定位函数那么就不能由写模式转为读模式。文件定位函数我们下节会介绍fflush函数稍微会介绍。 2.3、关闭文件fclose函数  fclose函数允许程序关闭不再使用的文件也叫作关闭文件流。fclose函数的参数必须是文件指针此指针来自fopen函数或freopen函数稍后介绍的调用如果成功关闭了文件flcose函数会返回零否则它会返回错误代码EOF。 ✔️实例见fopen函数实例程序员注意成对使用即可。 2.4、为已打开的流附加文件 freopen函数 freopen函数为已经打开的流附加一个不同的文件简单地说用于重定向输入输出流。最常见的用法是把文件和一个标准流前文介绍的3只相关联可以在不改变代码原貌的情况下改变输入输出环境。其中三个参数filename是需要重定向到的文件名或文件路径mode代表模式字符串stream是需要被重定向的文件流。 返回值通常是它的第三个参数文件指针如果无法打开文件则返回NULL。 ⭕️下面实例表示往foo文件写数据其中假设freopen返回值为NULL所以打不开foo文件。 if (freopen(foo, w, stdout) NULL) {//erro;foo can not be opened } 2.5、从命令行获取文件名  当正在编写的程序需要打开文件时就会出现一个问题如何把文件名提供给程序呢最好的解决方案是让程序从命令行获取文件的名字例如当执行名为demo的程序时可以通过把文件名放入命令行的方法为程序提供文件名 demo names.dat dates.dat 这里我们要通过定义带有两个形式参数的main函数来访问命令行参数我们下面介绍原理会的友友们可以直接跳过~ 2.5.1、命令行参数 运行程序时经常需要提供一些信息——文件名或者改变程序行为的开关如果我们要访问这些命令行信息参数必须通过把main函数定义为含有两个参数的函数来实现这两个参数通常命名为argc和argv。形式如下 int main(int argc, char* argv[]) {... } argc“参数计数”是命令行参数的数量包括程序名本身argv“参数向量”是指向命令行参数的指针数组这些命令行参数以字符串的形式存储argv[0]指向程序名而从argv[1]到argv[argc-1]则指向余下的命令行参数。 argv有一个附加元素即argv[argc]这个元素始终是一个空指针NULL。 ⭕️我们来看一个例子 如果用户输入命令行ls -l remind.c 这里的 ls 是Linux的命令ls 命令是“ list ”的缩写用于列出或显示目录的内容。而 ls -l 是 ls 的命令参数会以长列表格式显示文件内含文件的详细信息这里我们只介绍这一种参数还有很多关于 ls 命令的功能友友们下来可以了解了解  那么argc将为3argv[0]将指向含有程序名的字符串argv[1]将指向字符串“-l ”argv[2]将指向字符串“remind.c”而argv[3]将为空指针。如下图 图中没有详细的程序名因为操作系统的不同程序名可能会包括路径或其他信息如果程序名不可用那么argv[0]会指向空字符串。 因为argv是指针数组所以访问命令行参数非常容易常见的做法是期望有命令行参数的程序会设置循环来按顺序检查每一个参数。设定循环的方法之一就是使用整型变量作为argv数组的下标。例如下面的循环每行一条地显示命令行参数 int i; for (i 1; i argc; i) {printf(%s\n, argv[i]); } 另一种方法是构造一个指向argv[1]的指针argv[1]本就是指向字符的指针所以必须构造二级指针指向字符指针然后对指针重复进行自增操作来逐个访问数组余下的元素。因为argv数组的最后一个元素始终是空指针所以循环可以在找到数组中一个空指针时停止。例如 char** p; for (p argv[1]; *p ! NULL; p) {printf(%s\n, *p); } ⚠️注意这里我们设置了一个字符型二级指针p是指向字符的指针的指针pargv[1]是有意义的因为argv[1]是一个字符指针所以argv[1]就是指向指针的指针因为*p和NULL都是指针所以测试*pNULL没有问题p指向数组元素首元素地址所以p自增可以指向下一个字符printf中显示*p也是合理的因为*p指向字符串的第一个字符存放第一个字符地址字符串常量的内存储存是连续的所以可以直接打印出整个字符串。如果还是不太理解的友友可以学习一下二级指针再理解一下代码解释~ ⭕️通过上面的介绍我们基本清楚了如何定义带有两个形式参数的main函数来访问命令行参数我们回到从命令行获取文件名这一模块一起来看看之前提到的例子 demo names.dat dates.dat 我们已经知道argc是命令行参数的数量而argv是指向参数字符串的指针数组。argv[0]指向程序的名字从argv[1]到argv[argc-1]都指向剩余的实际参数而argv[argc]是空指针。在上述例子中argc为3argv[0]指向含有程序名的字符串argv[1]指向字符串“names.dat”argv[2]指向字符串“dates.dat”argv[3]指向空。所以我们就可以通过匹配命令行参数数量来判断文件是否具有文件名并且通过argv[]指针来找到文件名。 2.6、临时文件tmpfile函数和tmpnam函数  现实生活中程序经常需要产生临时文件即只在程序运行时存在的文件例如C编译器就常常产生临时文件。编译器可能先把c程序翻译成一些储存在文件中的中间形式稍后把程序翻译成目标代码时编译器就会读取这些文件。一旦程序完全通过了编译就不再需要保留那些含有程序中间形式的文件了。头stdio.h中提供了两个函数来处理临时文件即tmpfile函数和tmpnam函数。 tmpfile函数创建一个临时文件用“wb”模式打开该临时文件将一直存在除非关闭它或程序终止。tmpfile函数的调用会返回文件指针如果临时文件创建失败函数会返回空指针此指针可以用于稍后访问该文件。 FILE* tempptr; tmpptr tmpfile();//创建一个临时文件tmpptr是临时指针变量 ⚠️虽然tmpfile函数很易于使用但是它有两个缺点 ⭕️无法知道tmpfile函数创建的文件名是什么 ⭕️无法在以后使文件变为永久的。 如果这些缺点导致了问题那么备用方案就是用fopen函数产生临时文件因为我们不想让此文件与前面已存在的文件拥有相同的名字所以需要一个新函数产生新的文件名就是tmpnam函数。 tmpnam函数为临时文件产生名字。如果它的实际参数是空指针那么tmpnam函数会把文件名储存到一个静态变量中并且返回指向此变量的指针。  char* filename; ... filename tmpnam(NULL);//创建一个临时文件名 否则tmpnam函数会把文件名复制到程序员提供的字符数组中在这种情况下tmpnam函数一样会返回指向数组第一个字符的指针L_tmpnam是在头文件中定义的宏它指明了保存临时文件名的字符数组至少的长度 char filename[L_tmpnam]; ... tmpnam(filename); 2.7、文件缓冲fflush函数、setvbuf函数、setbuf函数  向磁盘驱动器传入数据或者从磁盘驱动器传出数据都是相对较慢的操作因此在每次程序想读或写入字符时都直接访问磁盘文件是不可行的。这时一个效率高的方法就是缓冲把写入流的数据存储在内存的缓冲区域内当缓冲区满了或者关闭流时对缓冲区进行“清洗”写入输出设备。比如printf函数在输出时是先输出到缓冲区然后才输出到屏幕上的输入流可以用类似的方法进行缓冲缓冲区包含来自输入设备的数据我们可以从缓冲区读取数据而不是从设备本身直接读取数据。缓冲区的存在大大提高了读取效率当然把缓冲区的内容传给磁盘或从磁盘传递给缓冲区也是需要花时间的但是大规模的“块”移动总比多次小字节速度快得多。✔️ 头stdio.h中的函数会在缓冲有用时自动进行缓冲操作。缓冲是在后台发生的但在极少的时候需要我们更主动的操作这就需要用到上述3个函数。 当程序向文件写输出时数据通常先放在缓冲区中。当缓冲区满了或者关闭文件时缓冲区会自动清洗向输出设备写入有时我们期望通过一定频率来清洗文件的缓冲区就需要调用fflush函数fflush函数的参数是指向指定缓冲流的FILE对象的指针如果函数调用成功则返回0否则返回EOF。下面调用的含义就是释放清洗指定流的缓冲区。 fflush(fp); 而如果需要清洗和fp相关联的文件那么就调用下面实例清洗了全部输出流 fflush(NULL);//flushes all buffers setvbuf函数允许改变缓冲流的方法并且允许控制缓冲区的大小和位置。也可以理解为该函数可指定流的缓冲区并且允许指定缓冲区的模式和大小(以字节为单位)。函数第一个参数是指向文件对象的指针该对象标识打开的流。函数的第二个参数是用户分配的缓冲区的地址长度至少为字节大小。如果设置为空指针该函数将自动分配一个缓冲区需指定缓冲区大小若调用成功函数返回0否则返回非0函数的第三个参数是期望的缓冲类型模式有三种缓冲类型分别定义为3个宏我们等会列表展示最后一个参数是缓冲区内字节的数量缓冲区大小较大的缓冲区可以提供较好的性能而较小的缓冲区可以节约空间。 下图为函数第三个参数——3个宏定义缓冲类型模式 其中全缓冲又叫满缓冲 ⚠️上述3个宏均在头stdio.h中定义对于没有与交互式设备相连的流来说满缓冲是默认设置。 ⭕️下面的例子调用setvbuf函数把buffer数组的N个字节作为缓冲区把stream的缓冲变成了满缓冲  char buffer[N]; ... setvbuf(stream,buffer,_IOFBF,N); setbuf函数是一个较早期的函数现在的新程序用得不多了它设定了缓冲模式和缓冲区大小的默认值。 如果buffer是空指针无缓冲那么setbufstream,buffer的调用就等价于 (void)setbuf(stream,NULL,_IONBF,0); 否则等价于满缓冲这里的BUFFERSIZ是在头文件中定义的宏 (void)setbuf(stream,buffer,_IOFBF,BUFFERSIZ); ⚠️注意使用setvbuf函数和setbuf函数时一定要确保在释放缓冲区之前已经关闭了流特别是如果缓冲区是局部于函数的并且有自动存储期一定要确保在函数返回之前关闭流。  2.8、其他文件操作remove函数和rename函数  remove函数和rename函数允许程序执行基本的文件管理操作。不同于其他文件处理函数这两个函数对文件名而不是文件指针进行处理操作不涉及流如果调用成功那么这两个函数都返回0否则都返回非0. ⭕️remove函数删除已经指定文件名的文件 remove(foo); //删除文件名为“foo”的文件 如果程序使用fopen函数而不是tmpfile函数因为tmpfile函数无法知道创建的临时文件的文件名是什么来创建临时文件那么它可以使用remove函数在程序终止前删除此文件。一定要确保已经关闭了要移除的文件因为对于当前打开的文件移除文件的效果是由实现定义的。 ⭕️rename函数改变文件的名字 rename(foo,bar); //改变文件名由“foo”变为“bar” 对于用fopen函数创建的临时文件如果程序需要使文件变为永久的那么用rename函数改名就可以了。如果具有新名字的文件已经存在了改名的效果会由实现定义。 ⚠️注意如果打开了要改名的文件一定要记住在调用rename函数之前关闭此文件对打开的文件执行改名操作会失败。  这里的实现定义英文名称是implementation-defined意为由编译器设计者来决定采取某种行动的这个词语提醒我们在实际编程时要考虑在多个运行环境下程序会产生不一样的结果的情况。 3、⭐️深入理解格式化输入输出⭐️printf,fprintf,scanf,fscanf函数 上节我们介绍了格式化输入输出的基本用法上节介绍的基本概念已经够我们前期使用这节我们继续对格式化输入输出函数进行深入介绍并介绍格式化输入输出函数与流结合的用法我们一起来看看吧~ 3.1、...printf函数与fprintf函数 fprintf和printf函数向输出流中写入可变数量的数据项并且利用格式串来控制输出的格式。这两个函数的定义原型都是以 ...省略号结尾的表明后面还可能有可变数量的实际参数。这两个函数的返回值都是写入的字符数若出错则返回一个负值。 fprintf函数与printf函数唯一不同的地方就是printf函数始终指向stdout标准输出流写入内容而fprintf函数则向它自己的第一个实际参数指定的流中写入内容。 printf(number:%d\n,number); //写入标准输出流fprintf(fp,number:%d\n,number); //写入fp所指向的流 ⭕️下面实例展示了调用fprintf函数向fp指定文件流中写入内容 #include stdio.h #include stdlib.h int main() {FILE* fp;fp fopen(C:\\Users\\樊双艺\\Desktop\\file.txt, w);fprintf(fp, %s %s %s %d, We, are, in, 2023);fclose(fp);return(0); } 文件显示内容如下  可以看出printf函数的调用等价于fprintf函数把stdout作为第一个实际参数而进行的调用。  ⭕️和stdio.h中其他函数一样fprintf函数不仅可以把数据写入磁盘文件还可以用于任何输出流事实上fprintf函数最常见的应用之一是——向标准误差流stderr写入出错消息和磁盘文件没有任何关系。下面调用类似实例 fprintf(stderr,Error:data file can not be opened.\n); 向stderr写入出错消息可以保证消息输出在屏幕上即使用户重定向stdout也没关系。  【在stdio.h中还有另外两个函数也可以向流写入格式化的输出分别是vfprintf函数和vprintf函数这两个函数都不太常见我们下节介绍。】 3.2、...printf函数转换说明 fprintf函数和printf函数都要求格式串包含普通字符或转换说明。普通字符会原样输出而转换说明则描述了如何把剩余的实参转换为字符格式显现出来。现在我们对上节课的转换说明内容进行回顾并补充深入内容。 ...printf函数的转换说明由字符%和跟随其后的最多5个不同的选项构成  下面进行解释选项的顺序必须与上面一致 标志可选项允许多于一个。标志 - 会导致数在栏内左对齐而其他标志会影响数的显示形式如下表 ⭕️示例标志作用于%d转换其他类似第一行显示了不带任何标志的效果接下来四行分别显示带有标志-、、空格、0的效果标志#从不用于%d关于#的示例会在介绍完转换指定符后展示。剩下几行为组合标志的效果 int main() {int i 123;printf( %8d\n, i);printf( %-8d\n, i);printf( %8d\n, i);printf( % 8d\n, i);printf( %08d\n, i);printf(%-8d\n, i);printf(%- 8d\n, i);printf(%08d\n, i);printf(% 08d\n, i);return 0; } 运行结果如下  分析如下  最小栏宽可选项要输出的字符的最小数目。如果数据太小以至于无法达到这一宽度那么会进行填充默认情况下会在数据的左侧添加空格从而使其在栏内右对齐。如果数据项过大以至于超过了这个宽度那么会完整的显示数据项。栏宽既可以是整数也可以是字符 * 。如果栏宽是字符 * 那么栏宽由下一个参数决定如果这个参数为负它会被视为前面带 - 标志的正数。 精度可选项精度的含义依赖于转换指定符如果转换指定符是d,i,o,u,x,X,那么精度表示最少位数如果位数不够则添加前导0如果转换指定符是a,A,e,E,f,F那么精度表示小数点后的位数如果转换指定符是g,G那么精度表示有效数字的个数如果转换指定符是s那么精度表示最大字节数。精度是由小数点 . 后跟一个整数或字符 * 构成的。如果出现字符 * 那么精度由下一个参数决定如果只有小数点则精度为0。 ⭕️示例最小栏宽和精度结合作用于转换说明%s的效果 int main() {char arr[10] bogus;printf( %6s\n, arr);printf( %-6s\n, arr);printf( %.4s\n, arr);printf( %6.4s\n, arr);printf(%-6.4s\n, arr);return 0; } 分析如下 长度指定符可选项。长度指定符配合转换指定符共同指定转入的实际参数的类型例如%d通常表示一个int值而%hd用于显示short int值%ld用于显示long int值。  另外C99中还定义了长度转换符hh字符型或无符号字符型 例如:signed char/unsigned char;以及长度指定符 j 和 t 这两个不常见我们以后遇到后介绍。 转换指定符n表中未指出适配于任何整型长度指定符长度类型符与转换说明结合时的类型均为指针类型。 转换指定符必有。 转换指定符必须是下表中列出的某一种字符。注意f、F、e、E、g、G、a和A全部设计用来输出double类型的值。但把它们用于float类型的值也可以由于有默认实参提升float类型实参在传递给带有可变数量实参的函数时会型自动转换为double类。类似的传递给...printf函数的字符也会自动转换为int类型所以可以正常使用转换指定符c。 注意 C99时新定义了a、A两个转换说明使用格式[-]0xh.hhhhp±d的格式把double类型转换为十六进制科学计数法形式。其中[-]是可选的负号h代表十六进制数位±是正号或负号d是指数d为十进制数表示2的幂。a表示用小写形式显示a-fA表示用大写形式显示A-F。 支持宽字符从C99开始就可以使用fprintf来输出宽字符。%le转换说明用于输出一个宽字符%ls用于输出一个由宽字符组成的字符串。 ⭕️示例说明了标志#作用于o、x、X、g、G转换效果 int main() {int i 123;printf( %8o\n, i);printf(%#8o\n, i);printf( %8x\n, i);printf(%#8x\n, i);printf( %8X\n, i);printf(%#8X\n, i);return 0; } 分析如下 ⭕️示例说明了%g转换如何以%e和%f的格式显示数 int main() {printf(%.4g\n, 123456.);printf(%.4g\n, 12345.6);printf(%.4g\n, 1234.56);printf(%.4g\n, 123.456);printf(%.4g\n, 12.3456);printf(%.4g\n, 1.23456);printf(%.4g\n, 0.123456);printf(%.4g\n, 0.0123456);printf(%.4g\n, 0.00123456);printf(%.4g\n, 0.000123456);printf(%.4g\n, 0.0000123456);printf(%.4g\n, 0.00000123456);return 0; } 分析如下 值得说说的是用字符 * 填充格式串往往会带来奇妙的结果我们来看一个例子 int main() {int i 123;printf(%6.4d\n, i);printf(%*.4d\n, 6, i);printf(%6.*d\n, 4, i);printf(%*.*d\n, 6, 4, i);return 0; } 可以看出这四次输出都完全相同用字符 * 取代最小栏宽度或者精度为字符 * 填充的值刚好出现在待显示的值之前。这就可以体现出字符 * 的优势就是在于它允许使用宏来指定栏宽或精度 printf(%*d,WIDTH); 3.3、...scanf函数与fscanf函数 fscanf函数和scanf函数从输入流读入数据并且使用格式串来指明输入的格式。格式串后面可以有任意数量的指针每个指针指向一个对象作为额外的实际参数。输入的数据项根据格式串中的转换说明进行转换并且存储在指针指向的对象中。  scanf函数始终从标准输入流stdin中读入内容而fscanf函数则从它的第一个参数所指定的流中读入内容 scanf(%d%d,i,j); //从标准输入流读入fscanf(fp,%d%d,i,j); //从指定流读入 可以看出scanf函数的调用等同于以stdin作为第一个实际参数的fscanf函数的调用。  ⚠️需要注意的是如果发生输入失败即没有输入字符可以读或者匹配失败即输入字符和格式串不匹配那么...scanf函数会提前返回。scanf和fscanf函数都返回读入并且赋值给对象的数据项的数量。如果在读取任何数据项之前发生输入失败那么会返回EOF。 3.4、...scanf函数格式串 scanf函数的调用类似于printf函数的调用但它们的工作原理完全不同我们常把scanf函数和fscanf函数看作“模式匹配函数”这个概念我们上节提过这里的匹配就是指scanf函数在读取输入时的输入的内容与格式串的匹配scanf函数是一个要求极其苛刻的函数它只要发现不匹配函数就会返回不再进行读取而不匹配的字符及其以后的字符将会被“放入原处”等待下一次读取。 scanf函数的格式串可能含有三种信息 转换说明scanf函数格式串中的转换说明类似于printf函数格式串中的转换说明。大多数的转换说明除了%[ 、%c、%n例外会跳过输入项开始处的空白字符。但是转换说明不会跳过尾部的空白字符。如果输入含有空格123回车那么转换说明%d会读取空格、1、2、3但是会留下回车不读取。又例如%d%d%d 是按十进值格式输入三个数值。输入时在两个数据之间可以用一个或多个空格、tab 键、回车键分隔。 空白字符scanf格式串中的一个或多个空白字符与输入流空白字符相匹配。 非空白字符包括一些普通字符除%外用户必须保证输入的内容与格式串字符相匹配。 3.5、...scanf函数转换说明 scanf函数的转换说明由字符%和跟随其后的下列选项按照出现的顺序构成 字符 * 可选项。字符 * 的出现意味着赋值屏蔽这是一个可选的星号表示数据是从流 stream 中读取的可以被忽视表示读入此数据但是不会把它赋值给对象。用 * 匹配的数据项不包含在scanf函数返回的计数中。注意区别于printf函数 最大栏宽可选项。最大栏宽限制了输入项字符的数量。注意printf函数中是最小栏宽如果达到了这个最大限度那么此数据项的转换将结束。转换开始处跳过的空白字符不进行统计。 长度指定符可选项。长度指定符表明用于存储输入数据项的对象的类型与特定转换说明中常见的类型长度不一致。与printf函数长度指定符只有 [ 字符不一样 转换指定符必有转换指定符必定是下表列出的某一种字符 解释如下  数值型数据项可以始终用符号或 -作为开头。然而说明符o,u,x,X把数据项转换成无符号的形式所以通常不用这些说明符来读取负数。 说明符 [ 是说明符s更加复杂更加灵活的版本使用 [ 的完整转换说明格式是%[集合]或者%[^集合] 这里的集合可以是任意字符集。但是如果 ] 是集合中的一个字符那么它必须首先出现。%[集合]匹配集合即扫描集合中的任意字符序列。%[^集合]匹配不在集合中的任意字符序列我们可以理解为数学上的补集我们匹配的就是补集的内容。例如%[abc]匹配的是只含有字母a,b,c的任何字符串而%[^abc]匹配的是不含有字母a,b,c的任何字符串。 ⭕️示例 #includestdio.h int main() {int a, b, c;printf(请输入三个数字);scanf(%d, %d, %d, a, b, c);printf(%d, %d, %d\n, a, b, c);return 0; } ⚠️使用scanf时一定要注意格式串的对应像上面的例子1,2,3之间必须输入逗号否则会造成匹配错误如下图 123会被当成第一个输入对象并存入a中接下来2与逗号不匹配scanf提前返回b和c的内容为无效值。  ⭕️示例   转换指定符 [ 的效果 #includestdio.h int main() {char str[20] { 0 };int n 0;n scanf(%[0123456789], str);printf(%d %s, n, str);return 0; } 可以看出对于转换说明%[0123456789]我们输入 123abc它只匹配含有0123456789的字符所以只输出123返回值为赋值给对象的数据项的数量。 3.6、检测文件末尾和错误条件clearerr函数、feof函数、ferror函数 我们知道...scanf函数读入并存储n个数据项那么我们就希望它的返回值就是n如果返回值小于n那么一定是出错了一共有三种情况 ✔️文件末尾。函数在完全匹配格式串之前遇到了文件末尾。 ✔️读取错误。函数不能从流中读取字符。 ✔️匹配失败。数据项的格式是错误的例如函数可能在搜索整数的第一个数字时遇到了一个字母。 但是如何知道遇到的情况是哪种呢❓ 每个流都有与之相关的两个指示器错误指示器和文件末尾指示器当打开流时会清除这些指示器。遇到文件末尾就设置文件末尾指示器遇到读错误就设置错误指示器。输出流上发生写错误时也会设置错误指示器。匹配失败不会改变任何一个指示器。 一旦设置了错误指示器或者文件末尾指示器他就会保持这种状态直到被显示的清除可能通过clearerr函数的调用。C 库函数 void clearerr(FILE *stream) 清除给定流 stream 的文件结束和错误标识符 clearerr(fp); //同时清除指定流的文件末尾指示器和错误指示器 因为其他库函数因为副作用可以清除某种指示器或两种都可以清除所以不需要经常使用clearerr函数。  我们可以调用feof函数和ferror函数来测试流的指示器从而确定出先前在流上的操作失败的原因。C 库函数 int feof(FILE *stream)会测试给定流 stream 的文件结束标识符如果为与fp相关的流设置了文件末尾指示器那么feof(fp)函数调用就会返回非零值。C 库函数 int ferror(FILE *stream) 会测试给定流 stream 的错误标识符。如果设置了错误指示器那么ferror(fp)函数的调用也会返回非零值而其他情况下这两个函数都会返回零。  如果我们想知道当scanf函数返回小于预期的值是什么情况可以使用feof函数和ferror函数来确定原因。如果feof函数返回了非零的值那么就说明已经到达了输入文件的末尾。如果ferror函数返回了非零的值那么就表示在输入过程中产生了读错误。如果两个函数都没有返回非零值那么一定是发生了匹配错误。不管问题是什么scanf函数的返回值都会告诉我们在问题产生前所读入的数据项的数量。 ⭕️我们来看一个示例应用feof和ferror函数自定义一个搜索文件中以整数起始的行,下面是自定义函数的调用其返回值赋值给n。 nfind_int(foo); 其中“foo”是要搜索文件的名字函数返回找到的整数的值并将其赋值给n如果出现问题文件无法打开或者发生读错误再或者没有以整数起始的行find_int函数将返回一个错误的值-1-2-3  int find_int(const char* filname) {FILE* fp fopen(filename, r);int n;if (fp NULL){return -1; //不能打开文件}while (fscanf(fp, %d, n) ! 1){if (ferror(fp)){fclose(fp);return -2; //输入错误}if (feof(fp)){fclose(fp);return -3; //找不到整数}scanf(fp, %*[^\n]);}fclose(fp);return n; } 分析 至此我们有关文件的基本操作以及对格式化输入输出的详细理解就结束了~~本节主要对文件的基本操作进行介绍下一节会对如何把单独的字符、一行数据和块数据怎么输入输出文件流进行介绍涉及函数putchar,getchar,fputc,fgetc行的输入输出puts,fputs,gets,fgets块的输入输出fread,fwrite以及字符串的输入和输出sprintf,snprintf,sscanf我们到时再进行详细介绍。 感谢各位友友们花费了宝贵的时间来阅读本篇文章创作不易希望大家多多支持呀如在阅读中发现任何问题欢迎各位友友大佬们在评论区指正支持❗️ ❗️ ❗️
http://www.ho-use.cn/article/10816193.html

相关文章:

  • 网站设计 联系网站空间知识
  • 泽成杭州seo网站推广排名网站建设工种
  • 免费erp系统网站建优化
  • 用户注册和登录网站怎么做的show t团队网站艰涩
  • 怎么可以建网站做定制网站
  • 网站创建服务公司集团网站建设要多少钱
  • 手机旅游视频网站模板一个专门做预告片的网站
  • 丽江做网站北京建筑公司一览表
  • 河池网站推广网站首页布局
  • h5响应式网站公司怎么做彩票网站
  • 网站备案接入商网站内链怎么删除
  • 网站建设招标评分标准西部数码网站打不开
  • 建wordpress外贸网站平台seo推广
  • 山东建设工程执业证书查询网站建筑用模板是什么板材
  • 做电商排名网站wordpress网站怎么加速
  • 企业网站建设发展平台淘宝客做网站好还是建群号
  • 泰安网站建设案例win8网站设计
  • 网站开发项目比赛wordpress企业模板中文版
  • 做韩国的跨境电商网站建设集团招聘
  • 长沙门户网站建设公司肇庆住房和城乡建设部网站
  • 能解析国外网站的dns网站开发先学什么
  • 网站注册界面设计音乐中文网站模板
  • 丹东网站开发哪些调查网站可以做问卷赚钱
  • 网站怎么挣钱物流公司网站开发与淘宝对接 在淘宝卖家中心显示物流信息
  • 如何做专题网站泉州网站关键词推广
  • 网站建设的开多少税率上海民营企业500强
  • 建设部网站监理公告村级网站模板
  • 网站建设项目可行性报告国内国际时事100字
  • 潍坊设计网站建设wordpress工单插件
  • 做幼儿英语的教案网站鲜花网站建设策划方案书