这篇文章要探讨的是“fgets()函数的详解以及使用时需要注意的一些细节”。涉及fgets()函数的应用和需要注意的问题。属于C语言基础篇(持续更新)。

fgets()(函数原型:char *fgets(char *restrict str, int size, FILE *restrict stream))

这个函数原型不太好看出个所以然来,可以理解为(char *fgets(“容器的地址”, “容器的大小”, “从哪里读取”))


一般用法:

char a[100] = {0};

fgets(a, 100, stdin);

通俗来讲的话,fgets()函数的作用就是用来读取一行数据的。但要详细且专业的说的话,fgets()函数的作用可以这么解释:从第三个参数指定的流中读取最多第二个参数大小的字符到第一个参数指定的容器地址中。在这个过程中,在还没读取够第二个参数指定大小的字符前,读取到换行符'\n'或者需要读取的流中已经没有数据了。则提前结束,并把已经读取到的字符存储进第一个参数指定的容器地址中。

在正常情况下fgets()函数的返回值和它第一个参数相同。即读取到数据后存储的容器地址。但是如果读取出错或读取文件时文件为空,则返回一个空指针。


fgets()函数的运行流程大概是这样子的:

当系统调用这个函数的时,系统便会阻塞等待用户的输入,直到用户输入回车符’\n’才返回程序。然后用户输入的内容会被系统放进输入缓存区里面,fgets()函数便会进来读取其“第二个参数减1(为什么减1后面说)”个字节存进它第一个参数指向的内存地址中,如果在还没读取够需要的字节大小前读取到换行符’\n’则提前返回。


fgets()函数的注意事项1

fgets()函数的最大读取大小是其“第二个参数减1”,这是由于字符串是以’\0’为结束符的,fgets()为了保证输入内容的字符串格式,当输入的数据大小超过了第二个参数指定的大小的时候,fgets()会仅仅读取前面的“第二个参数减1”个字符,而预留1个字符的空间来存储字符串结束符’\0’

测试代码:

#include <stdio.h>
int main(void)
{
char a[10] = {0};
printf("你的输入:");
fgets(a, 4, stdin);
//printf("%s\n", a);//下面这句的输出和这句是一样的
printf("printf(\"%%s\\n\", a)%c==>%s\n", ';', a);
return 0;
}

运行效果:

在这个例子中,fgets()的第二个参数是4,所以它最多只能存储输入的(4-1 = 3)个字符进第一个参数指向的地址空间里面。输入“abcde”,数组a[]中只有“abc”。


fgets()函数的注意事项2

fgets()函数的眼里,换行符’\n’也是它要读取的一个普通字符而已。在读取键盘输入的时候会把最后输入的回车符也存进数组里面,即会把’\n’也存进数组里面,而又由于字符串本身会是以’\0’结尾的。所以在输入字符个数没有超过第二个参数指定大小之前,你输入n个字符按下回车输入,fgets()存储进第一个参数指定内存地址的是n+2个字节。最后面会多出一个’\n’和一个’\0’,而且’\n’是在’\0’的前面一个(\n\0)。

测试代码:

#include <stdio.h>
int main(void)
{
char a[10] = {0};
printf("你的输入:");
fgets(a, 10, stdin);
//printf("%s\n", a);//下面这句的输出和这句是一样的
printf("printf(\"%%s\\n\", a)%c==>%s\n", ';', a);
for(int i=0; i<10; i++)
{
if(a[i] == '\n')
printf("a[%d]是换行符'\\n'\n", i);
if(a[i] == '\0')
printf("a[%d]是字符串结束符'\\0'\n", i);
}
return 0;
}

运行效果:



在这个例子中,由于输入的字符小于参数2指定的最大读取字符数,所以fgets()函数会把换行符’\n’也储存进数组a[]里面,在运行界面的第三行哪里换了两次行,就是由于这个多出来的换行符’\n’和我输出代码中的换行符’\n’共同作用的结果。


fgets()函数的注意事项3

fgets()函数只负责读取,并不会事先清空参数1指向的地址内存。读取到的字节会覆盖原地址储存,但没有覆盖到的内容还是保持原样。

测试代码:

#include <stdio.h>
int main(void)
{
char a[10] = {'1','1','1','1','1','1','1','1','1','1'};
printf("你的输入:");
fgets(a, 10, stdin);
//printf("%s\n", a);//下面这句的输出和这句是一样的
printf("printf(\"%%s\\n\", a)%c==>%s\n", ';', a);
for(int i=0; i<10; i++)
{
if(a[i] == '\n' || a[i] == '\0')
printf("a[%d] = '\\%c'", i, a[i]=='\n'?'n':'0');
else
printf("a[%d] = %c", i, a[i]);
printf("\n");
}
return 0;
}

运行结果:


fgets()函数的注意事项4

在用fgets()函数读取键盘输入的时候,如果输入多于其“第二个参数减1”个字符大小的数据,fgets()只会读取走前”第二个参数减1”个字符,多余的字符残留在输入缓存区里面。如果不清空,可能会影响下次输入。

测试代码:

#include <stdio.h>
int main(void)
{
char a[4] = {0};
char b[10] = {0};
printf("存进a的输入:");
fgets(a, 4, stdin);
for(int i=0; i<4; i++)
printf("a[%d] = %c\n", i, a[i]);
printf("存进b的输入:");
fgets(b, 10, stdin);
printf("这里没有阻塞等待输入,而是直接跳过了\n");
//printf("%s", a);//下面这句的输出和这句是一样的
printf("printf(\"%%s\", b)%c==>%s", ';', b);
return 0;
}

运行结果:

在这个例子中,输入“abcde”之后,数组a[]读取走“abc”之后,代码运行到第11行的时候并没有停下来等待用户的输入,而是直接读取了还留在缓存区里面的“de\n”,读取到‘\n’之后返回,所以我最后一行的输出代码中并没有加上换行符’\n’,因为数组b[]中已经包含有换行符’\n’了。


fgets()函数的注意事项5

遇到再更新。。。


原博客始发于CSDN,在如今博客界的转载抄袭泛滥的环境下,原创不易,点个赞再走呗。以下是博客首页的链接。


零BUG是原则性问题。

fgets()函数的详解以及使用时需要注意的一些细节-C语言基础的更多相关文章

  1. C语言对文件的操作函数用法详解1

    在ANSIC中,对文件的操作分为两种方式,即: 流式文件操作 I/O文件操作 一.流式文件操作 这种方式的文件操作有一个重要的结构FILE,FILE在stdio.h中定义如下: typedef str ...

  2. Go语言Slice作为函数参数详解

    Go语言Slice作为函数参数详解 前言 首先要明确Go语言中实质只有值传递,引用传递和指针传递是相对于参数类型来说. 个人认为上诉的结论不对,把引用类型看做对指针的封装,一般封装为结构体,结构体是值 ...

  3. Scala进阶之路-Scala函数篇详解

    Scala进阶之路-Scala函数篇详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.传值调用和传名调用 /* @author :yinzhengjie Blog:http: ...

  4. php中的PDO函数库详解

    PHP中的PDO函数库详解 PDO是一个“数据库访问抽象层”,作用是统一各种数据库的访问接口,与mysql和mysqli的函数库相比,PDO让跨数据库的使用更具有亲和力:与ADODB和MDB2相比,P ...

  5. C语言对文件的操作函数用法详解2

    fopen(打开文件) 相关函数 open,fclose 表头文件 #include<stdio.h> 定义函数 FILE * fopen(const char * path,const  ...

  6. MySQL UUID函数的详解(转)

    MySQL UUID函数的详解 MySQL中可以有二类用于生成唯一值性质的工具:UUID()函数和自增序列,那么二者有何区别呢?我们就此对比下各自的特性及异同点: l  都可以实现生成唯一值的功能: ...

  7. 自写函数VB6 STUFF函数 和 VB.net 2010 STUFF函数 详解

    '*************************************************************************'**模 块 名:自写函数VB6 STUFF函数 和 ...

  8. SQL Server数据库ROW_NUMBER()函数使用详解

    SQL Server数据库ROW_NUMBER()函数使用详解 摘自:http://database.51cto.com/art/201108/283399.htm SQL Server数据库ROW_ ...

  9. PHP函数篇详解十进制、二进制、八进制和十六进制转换函数说明

    PHP函数篇详解十进制.二进制.八进制和十六进制转换函数说明 作者: 字体:[增加 减小] 类型:转载   中文字符编码研究系列第一期,PHP函数篇详解十进制.二进制.八进制和十六进制互相转换函数说明 ...

  10. PHP date函数参数详解

    PHP date函数参数详解 作者: 字体:[增加 减小] 类型:转载       time()在PHP中是得到一个数字,这个数字表示从1970-01-01到现在共走了多少秒,很奇怪吧 不过这样方便计 ...

随机推荐

  1. java和js 用正则表达式切割省市县的代码

    String s= "安徽省合肥市肥西县上派镇"; // String regex="(\\?[^省]+自治区|.*?省|.*?行政区|.*?市)(\\?[^市]+自治州 ...

  2. SVD动态图

    library(gganimate) library(gifski) # 构造数据 phi<-pi/6 theta<-pi/3 c<-matrix(c(cos(phi),sin(ph ...

  3. Vulnhub 靶场 HMS?: 1

    Vulnhub 靶场 HMS?: 1 前期准备: 靶机地址:https://www.vulnhub.com/entry/hms-1,728/ 攻击机ip:192.168.147.190 靶机ip:19 ...

  4. pycharm中运行shell脚本

    为了跑一份深度学习工程文件,这份文件夹有好几份子文件夹,子文件夹里有.sh脚本.我以前跟盛哥来跑强化学习的代码时,盛哥教我装了git,所以用git是可以来跑脚本的.费力搞了半天装cygwin来跑,实际 ...

  5. HTML弹出对话框功能大全

    注://关闭,父窗口弹出对话框,子窗口直接关闭 this.Response.Write("<script language=javascript>window.close();& ...

  6. 2020ICPC上海I - Sky Garden

    思维 [I-Sky Garden_第 45 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(上海)(重现赛)@hzy0227 (nowcoder.com)](https://codeforces.co ...

  7. [node]启动一个简单的node接口

    来自知乎. 需要先安装一个node,安装过程不表. 新建文件: nodeServer.js // 复制这个文件到目录,再输入一下命令: // npm i express // node nodeSer ...

  8. Unity WebGL与JS脚本交互

    1.Unity调用JavaScript脚本方法 官网文档 老版本方法 之前Unity提供的Application.ExternalCall方法现在已经被设为过时弃用.(但是现在还能用,但是不知道什么时 ...

  9. 三分钟梳理TDengine安装部署的逻辑

      ​小 T 导读:TDengine,是涛思数据面对高速增长的物联网大数据市场和技术挑战推出的创新性的大数据处理产品,除却读写性能.存储压缩能力强大之外,还有安装简单.操作难度低等优势.今天我们就从常 ...

  10. 【2020NOI.AC省选模拟#5】C. 光滑序列

    题目链接 原题解: 光滑的序列一定有长度为$K$的循环节. 使用动态规划,设$F(i,j)$为使前$i$个整数的和为$j$的最小修改次数. 记$cost(i,v)$为令$A_i,A_{i+K},A_{ ...