首页 > 代码库 > 关于fputs和fgets的几个细节
关于fputs和fgets的几个细节
C语言中两个标准IO fputs和fgets都是针对行来进行数据的读取的!这里关于这两个IO函数我有几个小细节想在这里和大家分享一下,希望能够对大家产生帮助!
首先贴上这两个函数的函数声明,下面以这两个函数声明为基础进行讨论:
我用于调试的代码如下:
1 /* 本程序的输入为nihaoa,然后通过gdb调试来查看fputs的缓冲区内的内容 2 */ 3 #include<stdio.h> 4 #include<string.h> 5 #include<stdlib.h> 6 #include<errno.h> 7 8 #define MAXLINE 4 9 10 int main(int argc,char *argv[])11 {12 char buffer[MAXLINE];13 memset(buffer,1,MAXLINE);14 char buffer_o[BUFSIZ];15 memset(buffer_o,1,BUFSIZ);16 17 setbuf(stdout,buffer_o);18 19 while(NULL != fgets(buffer,MAXLINE,stdin))20 {21 if(EOF == fputs(buffer,stdout))22 {23 printf("[fputs]: %s",strerror(errno));24 exit(EXIT_FAILURE);25 }26 }27 28 if(ferror(stdin)) //检查上面循环停止是否是因为出错29 {30 printf("[fgets]: %s",strerror(errno));31 exit(EXIT_FAILURE);32 }33 34 buffer_o[6] = ‘k‘; 35 buffer_o[7] = ‘j‘;36 /* 这里我把fputs的缓冲区的内容调整了一下,最后一个换行字符变成了k,换行字符的后一个变成了j,但是fputs输37 * 出的时候还是输出了到k的内容,后面那个j并没有输出。所以fputs输出的时候并不是根据字符的最后一个‘\0‘来确38 * 定的,而是在这个程序内有个计数器,来计量一共输入了多少个字符,然后再来输出的。39 */40 41 return 0;42 }
首先说第一个问题,fgets每回从其缓冲区内读的数据的长度为SIZE-1个字节,然后它会自动在字符串末尾添加一个‘\0‘符号!而fgets将字符串存入其缓冲区的时候,会自动忽略末尾的‘\0‘符号!如下图所示:
就比如上面的那个程序!字符数组buffer用来充当这个程序的缓冲区!而那个buffer_o我通过setbuf函数来让它变成了标准输出的缓冲区!为了便于区分,我把这两个数组的数据初始化全部设置为1.
举个例子,比如我在上面那个程序的19行和21行设置两个个断点!然后运行查看buffer的内存!
首先是第19行的,此时buffer的内存全部都是1:
然后运行一句,我输入的数据是nihaoa<CR>,由于buffer的内容不够大,所有它只会读size-1也就是3个字节的内容,最后一个字节填充为0,如下图所示:
上面这个就说明了关于fgets的内容,它只从它的缓冲区中读取size-1个字节,然后在字符串的尾部加上一个0;
接下来我们接着调试,继续来向下运行一步,其结果如下图所示:
这里这个buffer_o是stdout的缓冲区,此时它里面只有3个字节的内容,这正好说明了关于fputs的部分,从目标内存中读取字符串,并且忽略掉字符串尾部的‘\0‘。
接着我们再来说第二个问题,那就是fputs程序内部应该有一个计数器,用来统计stdout的缓冲区中一共有多少个字符,fputs输出的时候就是根据这个计数器来输出!我们还是以上面那段代码为例,这回我们在34行和40行设置一个断点。再来看buffer_o这片内存中的内容!如下图所示:
这回我的输入还是nihaoa<CR>,这回stdout的缓冲区中放的内容就是nihaoa<CR>的ASCII码了!然后我把那个回车和回车的下一个的ASCII码改一下,如下图所示:
回车字符变成了k,它的下一个变成了j。然后我们再来查看输出的结果!
由于gdb自动添加了一个换行符,所以我就以普通方式运行查看了!如下图所示:
最后的输入是nihaoak,并没有多,这里就说明fgets的输出是根据它的那个计数器来的!
关于fputs和fgets的几个细节