关于fputs和fgets的几个细节
C语言中两个标准IO fputs和fgets都是针对行来进行数据的读取的!这里关于这两个I O函数我有几个小细节想在这里和大家分享一下,希望能够对大家产生帮助!
首先贴上这两个函数的函数声明,下面以这两个函数声明为基础进行讨论:
我用于调试的代码如下:
1/* 本程序的输入为nihaoa,然后通过gdb调试来查看fputs的缓冲区内的内容
2*/
3#include
4#include
5#include
6#include
7
8#define MAXLINE 4
9
10int main(int argc,char*argv[])
11{
12char buffer[MAXLINE];
13memset(buffer,1,MAXLINE);
14char buffer_o[BUFSIZ];
15memset(buffer_o,1,BUFSIZ);
16
17setbuf(stdout,buffer_o);
18
19while(NULL != fgets(buffer,MAXLINE,stdin))
20{
21if(EOF == fputs(buffer,stdout))
22{
23printf("[fputs]: %s",strerror(errno));
24exit(EXIT_FAILURE);
25}
26}
27
28if(ferror(stdin)) //检查上面循环停止是否是因为出错
29{
30printf("[fgets]: %s",strerror(errno));
31exit(EXIT_FAILURE);
32}
33
34buffer_o[6] = 'k';
35buffer_o[7] = 'j';
36/* 这里我把fputs的缓冲区的内容调整了一下,最后一个换行字符变成了k,换行字符的后一个变成了j,但是fputs输
37* 出的时候还是输出了到k的内容,后面那个j并没有输出。所以fput s输出的时候并不是根据字符的最后一个'\0'来确
38* 定的,而是在这个程序内有个计数器,来计量一共输入了多少个字符,然后再来输出的。
39*/
40
41return0;
42}
首先说第一个问题,fgets每回从其缓冲区内读的数据的长度为SIZE-1个字节,然后它会自动在字符串末尾添加一个'\0'符号!而fgets将字符串存入其缓冲区的时候,会自动忽略末尾的'\0'符号!如下图所示:
就比如上面的那个程序!字符数组buffer用来充当这个程序的缓冲区!而那个buffer_o 我通过setbuf函数来让它变成了标准输出的缓冲区!为了便于区分,我把这两个数组的数据初始化全部设置为1.
举个例子,比如我在上面那个程序的19行和21行设置两个个断点!然后运行查看buffer 的内存!
首先是第19行的,此时buffer的内存全部都是1:
然后运行一句,我输入的数据是nihaoa
上面这个就说明了关于fgets的内容,它只从它的缓冲区中读取size-1个字节,然后在字符串的尾部加上一个0;
接下来我们接着调试,继续来向下运行一步,其结果如下图所示:
这里这个buffer_o是stdout的缓冲区,此时它里面只有3个字节的内容,这正好说明了关于fputs的部分,从目标内存中读取字符串,并且忽略掉字符串尾部的'\0'。
接着我们再来说第二个问题,那就是fputs程序内部应该有一个计数器,用来统计stdout 的缓冲区中一共有多少个字符,fputs输出的时候就是根据这个计数器来输出!我们还是以上面那段代码为例,这回我们在34行和40行设置一个断点。再来看buffer_o这片内存中的内容!如下图所示:
这回我的输入还是nihaoa
回车字符变成了k,它的下一个变成了j。然后我们再来查看输出的结果!
由于gdb自动添加了一个换行符,所以我就以普通方式运行查看了!如下图所示:
最后的输入是nihaoak,并没有多,这里就说明fgets的输出是根据它的那个计数器来的!
getch()和getchar() getchar()是C的标准库函数,包含在头文件
fgets函数 从流中读一行或指定个字符, 原型是char *fgets(char *s, int n, FILE *stream); 从流中读取n-1个字符,除非读完一行,参数s是来接收字符串,如果成功则返回s的指针,否则返回NULL。 形参注释:*string结果数据的首地址;n-1:一次读入数据块的长度,其默认值为1k,即1024;stream文件指针 例:如果一个文件的当前位置的文本如下 Love ,I Have But ........ 如果用 fgets(str1,4,file1); 则执行后str1="Lov",读取了4-1=3个字符, 而如果用 fgets(str1,23,file1); 则执行str="Love ,I Have",读取了一行(不包括行尾的'n')。 序例: #include
char string[] = "This is a test"; char msg[20]; /* open a file for update */ stream = fopen("DUMMY.FIL", "w+"); /* write a string into the file */ fwrite(string, strlen(string), 1, stream); /* seek to the start of the file */ fseek(stream, 0, SEEK_SET); /* read a string from the file */ fgets(msg, strlen(string)+1, stream); /* display the string */ printf("%s", msg); fclose(stream); return 0; } fgets函数用来从文件中读入字符串。fgets函数的调用形式如下:fgets(str,n,fp);此处,fp是文件指针;str是存放在字符串的起始地址;n是一个int类型变量。函数的功能是从fp所指文件中读入n-1个字符放入str为起始地址的空间内;如果在未读满n-1个字符之时,已读到一个换行符或一个EOF(文件结束标志),则结束本次读操作,读入的字符串中最后包含读到的换行符。因此,确切地说,调用fgets函数时,最多只能读入n-1个字符。读入结束后,系统将自
------------------------------------------------------------------- | 问题描述一:(分析scanf()和getchar()读取字符)| ------------------------------------------------------------------- scanf(), getchar()等都是标准输入函数,一般人都会觉得这几个函数非常简单,没什么特殊的。但是有时候却就是因为使用这些函数除了问题,却找不出其中的原因。下面先看一个很简单的程序: 程序1: #include
ch2 = getchar(); printf("%d %d\n", ch1, ch2); return 0; } 程序的本意很简单,就是从键盘读入两个字符,然后打印出这两个字符的ASCII码值。可是执行程序后会发现除了问题:当从键盘输入一个字符后按下回车准备输入第二个字符时,就打印出了结果,根本就没有输入第二个字符程序就结束了。例如用户输入字符'a'回车, 打印结果是97,10(回车)。输入字符'a'-空格-‘b’,结果为97 32也就是说ch2接收的是空格而不是’b’。这是为什么呢? 【分析】: 首先我们呢看一下输入操作的原理,程序的输入都建有一个缓冲区,即输入缓冲区。一次输入过程是这样的,当一次键盘输入结束时(按下回车键)会将输入的数据全部存入输入缓冲区(包括空格和回车),而输入函数直接从输入缓冲区中取数据。正因为输入函数是直接从缓冲区取数据的,所以有时候当缓冲区中有残留数据时,输入函数会直接取得这些残留数据而不会请求键盘输入,这就是例子中为什么会出现输入语句失效的原因! 其实这里的10恰好是回车符!这是因为scanf()和getchar()函数是从输入流缓冲区中读取值的,而并非从键盘(也就是终端)缓冲区读取。而读取时遇到回车(\n)而结束的,这个\n会一起读入输入流缓冲区的,所以第一次接受输入时取走字符后会留下字符\n,这样
文件打开函数fopen fopen函数用来打开一个文件,其调用的一般形式为: 文件指针名=fopen(文件名,使用文件方式) 其中,“文件指针名”必须是被说明为FILE 类型的指针变量,“文件名”是被打开文件的文件名。“使用文件方式”是指文件的类型和操作要求。“文件名”是字符串常量或字符串数组。例如: FILE *fp; fp=("file a","r"); 其意义是在当前目录下打开文件file a,只允许进行“读”操作,并使fp指向该文件。 -------------------------------------------------------------------------------- -- C语言的文件操作 FILE *fphzk fphzk=("c:\\hzk16',"rb") 其意义是打开C驱动器磁盘的根目录下的文件hzk16,这是一个二进制文件,只允许按二进制方式进行读操作。两个反斜线“”中的第一个表示转义字符,第二个表示根目录。使用文件的方式共有12种,下面给出了它们的符号和意义。 文件使用方式意义 “rt”只读打开一个文本文件,只允许读数据 “wt”只写打开或建立一个文本文件,只允许写数据 “at”追加打开一个文本文件,并在文件末尾写数据 “rb”只读打开一个二进制文件,只允许读数据 “wb”只写打开或建立一个二进制文件,只允许写数据 “ab”追加打开一个二进制文件,并在文件末尾写数据 “rt+”读写打开一个文本文件,允许读和写 “wt+”读写打开或建立一个文本文件,允许读写 “at+”读写打开一个文本文件,允许读,或在文件末追加数据 “rb+”读写打开一个二进制文件,允许读和写 “wb+”读写打开或建立一个二进制文件,允许读和写 “ab+”读写打开一个二进制文件,允许读,或在文件末追加数据 对于文件使用方式有以下几点说明: 1. 文件使用方式由r,w,a,t,b,+六个字符拼成,各字符的含义是: r(read): 读 w(write): 写 a(append): 追加 t(text): 文本文件,可省略不写 b(banary): 二进制文件 +: 读和写 2. 凡用“r”打开一个文件时,该文件必须已经存在,且只能从该文件读出。
文件操作函数: 打开方式的取值和意义如下: ◆"r":该打开方式为只读方式 ◆"w":该打开方式为只写方式 ◆"a":该打开方式为尾加方式 ◆"r+":该打开方式为读/写方式,相当于"r"与"w"方式的结合。 ◆"w+":该打开方式为读/写方式,相当于"r"与"w"方式的结合。 ◆"a+":该打开方式为读/尾加方式 ◆"rb":该打开方式为只读方式 ◆"wb":该打开方式为只写方式 ◆"ab":该打开方式为尾加方式 ◆"rb+":该打开方式为读/写方式,相当于"rb"与"wb"方式的结合。 ◆"wb+":该打开方式为读/写方式,相当于"rb"与"wb"方式的结合。 ◆"ab+":该打开方式为读/尾加方式 打开文件:fopen( "文件路径",“使用文件方式”)。 关闭文件: fclose( 文件指针)。 char fgetc(FILE *p); 函数读取参数p指向的文件。fgetc函数返回一个字符。 处理读取结束:对于文本文件,如果读取位置到达文件末尾,fgetc函数返回一个结束标志EOF ; ANSI C提供了一个feof(FILE *p) 函数,当fgetc函数读取到文件末尾时,feof(FILE *p)函数返回1,否则返回0。 char * fgets(char str[],int n,FILE *p) ; 函数读取参数p指向的文件每次调用fgets(char str[],int n,FILE *p) 就顺序地读取n个字节,如此顺序地读取,直到读取的n个字节包含文件的结束标志。 fgets函数按文本方式读取文件,如果读取的n个字节中含有文件的结束标志EOF,fgets函数返回NULL。 char fputs(char str[],FILE *p); 向参数p指向的文件写入字符数组str。每次调用fputs函数就顺序地向文件中写入字符串str,如此顺序地写入,直到停止调用fputs函数或发生写入错误。
深入了解scanf()/getchar()和gets()/cin等函数 问题描述一:(分析scanf()和getchar()读取字符) scanf(), getchar()等都是标准输入函数,一般人都会觉得这几个函数非常简单,没什么特殊的。但是有时候却就是因为使用这些函数除了问题,却找不出其中的原因。下面先看一个很简单的程序: 程序1: #include
C语言文件读写函数 1.fopen() fopen的原型是:FILE *fopen(const char *filename,const char *mode),fopen 实现三个功能:为使用而打开一个流,把一个文件和此流相连接,给此流返回一个FILR指针。 参数filename指向要打开的文件名,mode表示打开状态的字符串,其取值如下: 字符串含义 "r" 以只读方式打开文件 "w" 以只写方式打开文件 "a" 以追加方式打开文件 "r+" 以读/写方式打开文件,如无文件出错 "w+" 以读/写方式打开文件,如无文件生成新文件 一个文件可以以文本模式或二进制模式打开,这两种的区别是:在文本模式中回车被当成一个字符’/n’,而二进制模式认为它是两个字符0x0D,0x0A;如果在文件中读到0x1B,文本模式会认为这是文件结束符,也就是二进制模型不会对文件进行处理,而文本方式会按一定的方式对数据作相应的转换。
系统默认的是以文本模式打开,可以修改全部变量_fmode的值来修改这个设置,例如_fmode=O_TEXT;就设置默认打开方式为文本模式;而 _fmode=O_BINARY;则设置默认打开方式是二进制模式。 我们也可以在模式字符串中指定打开的模式,如"rb"表示以二进制模式打开只读文件,"w+t"或"wt+"表示以文本模式打开读/写文件。 此函数返回一个FILE指针,所以申明一个FILE指针后不用初始化,而是用fopen()来返回一个指针并与一个特定的文件相连,如果成败,返回NULL. 例: 以下是引用片段: FILE *fp; if(fp=fopen("123.456","wb")) puts("打开文件成功"); else puts("打开文件成败"); 2.fclose() fclose()的功能就是关闭用fopen()打开的文件,其原型是:int fclose(FILE *fp);如果成功,返回0,失败返回EOF。 在程序结束时一定要记得关闭打开的文件,不然可能会造成数据丢失的情况,我以前就经常犯这样的错误。 例:fclose(fp); 3.fputc()
fgets函数详解 fgets函数详解 fgets函数从流中读一行或指定个字符, 原型是char *fgets(char *s, int n, FILE *stream); 从流中读取n-1个字符,除非读完一行,参数s是来接收字符串,如果成功则返回s 的指针,否则返回NULL。 形参注释:*s结果数据的首地址;n-1:一次读入数据块的长度,其默认值为1k,即1024;stream文件指针 例:如果一个文件的当前位置的文本如下 Love ,I Have But ........ 如果用 fgets(str1,4,file1); 则执行后str1="Lov",读取了4-1=3个字符, 而如果用 fgets(str1,23,file1); 则执行str="Love ,I Have",读取了一行(包括行尾的'\n',并自动加上字符串结束符'\0')。编辑本段序例: #include
C/C++学习笔记1 - 深入了解scanf()/getchar()和gets()等函数 ---------------------------------------------------- | 问题描述一:(分析scanf()和getchar()读取字符) | ---------------------------------------------------- scanf(), getchar()等都是标准输入函数,一般人都会觉得这几个函数非常简单,没什么特殊的。但是有时候却就是因为使用这些函数除了问题,却找不出其中的原因。下面先看一个很简单的程序: 程序1: #include
VC读写函数详解 1.当前文件指针位置获取函数 long ftell( FILE *stream ); 参数:stream 文件指针 返回值:当前文件指针的位置 实例: #include
从零开始学习C语言(一)之读取文本文件(函数fgets) - seven - 51CTO.txt你站在那不要动!等我飞奔过去!雨停了天晴了女人你慢慢扫屋我为你去扫天下了 你是我的听说现在结婚很便宜,民政局9块钱搞定,我请你吧你个笨蛋啊遇到这种事要站在我后面!跟我走总有一天你的名字会出现在我家的户口本上。从零开始学习C语言(一)之读取文本文件(函数fgets) - seven - 51CTO技术博客51CTO 首页我的博客搜索社区:论坛博客下载读书更多 登录注册家园 博客 论坛 下载 自测 门诊 周刊 读书 技术圈 知道 https://www.doczj.com/doc/b92750968.html, 【复制】【订阅】原创:125翻译:1转载:62 博客|图库|写博文|帮助 首页|应用代理|数据库|程序设计|监控系统|负载优化|虚拟化|系统工具|C语言|svn&trac&bug|业界生活|生活锁事|puppet 守住每一天 的BLOG 写留言邀请进圈子发消息加友情链接进家园加好友 博客统计信息 51cto博客之星 用户名:守住每一天 文章数:188 评论数:655 访问量:323162 无忧币:6061 博客积分:5748 博客等级:8 注册日期:2007-06-13 热门文章 nginx反向代理配置及优化 从零开始学习C语言(一).. apache+jk+tomcat集群+se.. umount 的时候报错:devic.. mysql+mmm+proxy实现mysq.. nagios 3.X 简单部署及应用 ntop安装过程 我用nagios-check_http .. HTTP 错误 401.1(401.2/4.. 暂时的失业和降薪,是为.. 解决tomcat死掉JK无法连..
~~~~~~~~~~##打印了好好学习##~~~~~~~~~~歪诗协会QQ978107204 C语言文件操作函数大全 相关函数feof 表头文件#include
深入了解scanf()/getchar()/gets()/getch,getche ---------------------------------------------------- | 问题描述一:(分析scanf()和getchar()读取字符)| ---------------------------------------------------- scanf(), getchar()等都是标准输入函数,一般人都会觉得这几个函数非常简单,没什么特殊的。但是有时候却就是因为使用这些函数除了问题,却找不出其中的原因。下面先看一个很简单的程序: 程序1: #include
ch1 = getchar(); ch2 = getchar(); printf("%d %d\n", ch1, ch2); return 0; } 程序的本意很简单,就是从键盘读入两个字符,然后打印出这两个字符的ASCII码值。可是执行程序后会发现除了问题:当从键盘输入一个字符后,就打印出了结果,根本就没有输入第二个字符程序就结束了。例如用户输入字符'a', 打印结果是97,10。这是为什么呢?【分析】: 首先我们呢看一下输入操作的原理,程序的输入都建有一个缓冲区,即输入缓冲区。一次输入过程是这样的,当一次键盘输入结束时会将输入的数据存入输入缓冲区,而cin函数直接从输入缓冲区中取数据。正因为cin函数是直接从缓冲区取数据的,所以有时候当缓冲区中有残留数据时,cin函数会直接取得这些残留数据而不会请求键盘输入,这就是例子中为什么会出现输入语句失效的原因! 其实这里的10恰好是回车符!这是因为scanf()和getchar()函数是从输入流缓冲区中读取值的,而并非从键盘(也就是终端)缓冲区读取。而读取时遇到回车(\n)而结束的,这个\n会一起读入输入流缓冲区的,所以第一次接受输入时取走字符后会留下字符\n,这样第二次的读入函数直接从缓冲区中把\n取走了,显然读取成功了,所以不会再从终端读取!这就是为什么这个程序只执行了一次输入操作就结束
scanf(), getchar(), 以及gets()函数注意点 --------------------------------------------------- | 问题描述一:(分析scanf()和gets()读取字符) | ---------------------------------------------------- scanf(), getchar()等都是标准输入函数,一般人都会觉得这几个函数非常简单,没什么特殊的。但是有时候却就是因为使用这些函数出了问题,却找不出其中的原因。下面先看一个很简单的程序: 程序1: #include
C语言文件操作常用函数 详解 This model paper was revised by the Standardization Office on December 10, 2020
C语言文件操作详解 在C语言文件操作的过程中,通常有以下几种方式: 1.单个字符的操作: fputc 函数原型:intfputc(intc,FILE*fp); 功能:把一字节代码c写入fp指向的文件中 返回值:正常,返回c;出错,为EOF(-1) fgetc 函数原型:intfgetc(FILE*fp); 功能:从fp指向的文件中读取一字节代码 返回值:正常,返回读到的代码值;读到文件尾或出错,为EOF(-1) feof 函数原型:intfeof(FILE*fp); 功能:判断文件是否到末尾 返回值:文件未结束,返回0;文件结束,返回真(非0)示例: #include
C语言学习常用函数 1.strstr()和strrchr()if (strstr(buff, "ION BETA") != NULL)判断 包含文件:string.h 函数名: strstr 函数原型:extern char *strstr(const char *str1, const char *str2); 语法:* strstr(str1,str2) str1: 被查找目标string expression to search. str2: 要查找对象The string expression to find. 返回值:若str2是str1的子串,则先确定str2在str1的第一次出现的位置,并返回此位置到str1末尾的所有字符;如果str2不是str1的子串,则返回NULL。(注:若想返回str2在str1第一次出现的位置,不是这个函数)。 例子: charstr[]="1234xyz"; char*str1=strstr(str,"34"); cout<
C++中cin、cin.get()、cin.getline()、getline()、gets()等函数的用法 学C++的时候,这几个输入函数弄的有点迷糊;这里做个小结,为了自己复习,也希望对后来者能有所帮助,如果有差错的地方还请各位多多指教(本文所有程序均通过VC 6.0运行) 1、cin 2、cin.get() 3、cin.getline() 4、getline() 5、gets() 6、getchar() 附:cin.ignore();cin.get()//跳过一个字符,例如不想要的回车,空格等字符 1、cin>> 用法1:最基本,也是最常用的用法,输入一个数字: #include
#include
gets从标准输入设备读字符串函数。可以无限读取,不会判断上限,以回车结束读取,所以程序员应该确保buffer的空间足够大,以便在执行读操作时不发生溢出。 原型 char * gets ( char * str ); 功能 从stdin流中读取字符串,直至接受到换行符(Enter)或EOF(关闭)时停止,并将读取的结果存放在buffer指针所指向的字符数组中。换行符不作为读取串的内容,读取的换行符被转换为‘\0’空字符,并由此来结束字符串。 返回值 读入成功,返回与参数buffer相同的指针;读入过程中遇到EOF(End-of-File)或发生错误,返回NULL指针。所以在遇到返回值为NULL的情况,要用ferror或feof函数检查是发生错误还是遇到EOF。 注意 本函数可以无限读取,不会判断上限,所以程序员应该确保buffer的空间足够大,以便在执行读操作时不发生溢出。如果溢出,多出来的字符将被写入到堆栈中,这就覆盖了堆栈原先的内容,破坏一个或多个不相关变量的值。这个事实导致gets函数只适用于玩具程序,为了避免这种情况,我们可以用fgets(stdin) (fgets实际上可以读取标准输入(即大多数情况下的键盘输入),具体参阅fgets词条)来替换gets()。在V7的手册(1979年)中说明:为了向后兼容,gets删除换行符,gets并不将换行符存入缓冲区。 示例: #include
char str1[5]; //不要char*p,然后gets(p),这是错误的,因为p没有指向有效的内存,它可能指向任何 // 地方的未知大小的内存块,这样以来,就可能修改了不属于本程序的内存的内容 gets(str1); printf("%s\n", str1); return0; } gets(s)函数与scanf("%s",s)相似,但不完全相同,使用scanf("%s",s) 函数输入字符串时存在一个问题,就是如果输入了空格会认为字符串结束,空格后的字符将作为下一个输入项处理,但gets()函数将接收输入的整个字符串直到遇到换行为止。 也就是说:gets()函数读取到\n(我们输入的回车)于是停止读取,即只能输入一行,但是它不会把\n包含到字符串里面去。然而,和它配合使用的puts函数,却在输出字符串的时候自动换行(即不再同一行内,在新的一行)。