在c语言中读取字符串有多种方法,比如scanf() 配合%s使用,但是这种方法只能获取一个单词,即遇到空格等空字符就会返回。如果要读取一行字符串,比如:

I love BIT

这种情况,scanf()就无能为力了。这时我们最先想到的是用gets()读取.

gets()函数从标准输入(键盘)读入一行数据,所谓读取一行,就是遇到换行符就返回。gets()函数并不读取换行符'\n',它会吧换行符替换成空字符'\0',作为c语言字符串结束的标志。

gets()函数经常和puts()函数配对使用,puts()函数用于显示字符串,并自动在字符串后面添加一个换行标志'\n'

gets()函数存在一个严重的缺陷,这个缺陷就是:它不会检查数组是否能够装的下输入行:

比如:

我们定义了一个数组char src[5],这时候我们调用gets(src),来从标准输入读取字符串,我们看到gets()函数的参数为数组名,我们都知道,数组名就相当于一个指针,也就是数组的首地址。这时如果我们的输入大于5个字符,比如 I love BIT,gets()函数会从src所指地址开始,依次填入每个字符,但是src只分配了5个字节的空间,填满这五个空间后,gets()函数就会访问未被分配的内存空间,如果这片空间已经存有数据,这时程序就会发生错误,而中断。

正式由于gets()函数的这个缺陷,在C99标准中,已经不再建议使用gets()函数,而在C11中更是直接抛弃了这个函数。

gets()被抛弃,那我们用什么来代替它的功能呢?

C11标准新增了gets_s()函数可以代替gets()函数,但是,该函数是stdio.h输入输出函数系类中的可选扩展,因此,即使编译器支持C11标准,也有可能不支持gets_s()函数。

其实我们可以用c语言中的fgets()函数来代替gets()

我们先看一下函数原型声明:

char *fgets(char *buf, int bufsize, FILE *stream);

注意一下第二个参数bufsize,这个参数就限制了读取的字符的个数,这就可以解决gets()函数的缺陷。

我们知道fgets() 函数主要用于读取文件,如果要读取键盘,则stream参数应该为stdin,

需要注意的是,如果bufsize设置为n,那么fgets()函数最多读取n-1个字符,之所以用“最多”这个词是因为,如果在之前遇到了换行符,fgets函数也会返回。

还有一点就是,fgets()函数会读取换行符(这一点和gets函数不同),当读取结束后,fgets函数会为buf在末尾添加一个空字符作为字符串的结束。

可以看一个简单的小例子:

#include <stdio.h>
#include <stdlib.h>
#define LEN 6
int main(int argc,char* argv[])
{
char src[LEN];
printf("please enter:\n");
fgets(src,LEN,stdin);
printf("your enter is:\n");
fputs(src,stdout);
}

在这个程序中,我把数组的长度设置为6,先看一组输入和输出:

输入为zhan和回车('\n'),一共五个字符,fgets会读取这五个字符,然后在末尾添加字符串结束标志'\0';

我们知道fputs()函数并不会自动添加换行,但是输出结果却换行输出了Press any....,这就说明了fgets()函数是会读取换行符的。

在看一组输入输出:

这次我输入了zhang和回车换行,fgets函数依然是读取5个字符(LEN-1个),这时fgets()读入zhang,已经是五个字符了,所以回车换行并不会读入,最后fgets()添加字符串结束标志'\0',所以我们看到输出时,Press any...并没有换行输出,而是和zhang在同一行。

最后看一组输入和输出:

相信不用解释大家也都明白了。

总结一下就是:

gets函数没有限制读入的个数,这很可能会导致程序向未知的内存空间写入数据,而导致程序出错。

fgets函数中第二个参数限制了读取的个数,这也解决了gets函数存在的问题,但要注意fgets函数只会读取n-1个字符(如果遇到换行符会更少),并在最后添加字符串结束标志,而且,fgets也会将换行符读入。

c语言gets()函数与它的替代者fgets()函数的更多相关文章

  1. gets,gets_s,fgets函数

    这次就说一下,gets(),gets_s(),fgets(),::::[在某一篇博客上看到的] C的标准库gets函数不对接受字符串的buffer进行边界检测,会造成越界,从而产生bug: fgets ...

  2. 三种语言(c++、as、lua)中函数的差异性

    对于不同的语言, 尤其是静态语言和动态语言, 对于函数的定义(即如何看待一个函数)和处理截然不同.具体来说可以分为两类: 1.将函数视为第一类型值, 即函数和其他的对象一样, 都是语言中一个普通的对象 ...

  3. C语言常用的库文件(头文件、函数库)

    C语言常用的库文件(头文件.函数库) C系统提供了丰富的系统文件,称为库文件.C的库文件分为两类,一类是扩展名为".h"的文件,称为头文件,在前面的包含命令中我们已多次使用过.在& ...

  4. R语言学习 第八篇:常用的数据处理函数

    Basic包是R语言预装的开发包,包含了常用的数据处理函数,可以对数据进行简单地清理和转换,也可以在使用其他转换函数之前,对数据进行预处理,必须熟练掌握常用的数据处理函数,本文分享在数据处理时,经常使 ...

  5. 程序设计入门-C语言基础知识-翁恺-第五周:函数-详细笔记(五)

    目录 第五周:函数 5.1 函数 5-2 使用函数 5.3 课后习题 第五周:函数 5.1 函数 什么是函数? 函数是一块代码,接受零个或多个参数,做一件事情,并返回零个或一个值. 函数声明语法 返回 ...

  6. C++对C语言的拓展(2)—— inline内联函数

    C语言中有宏函数的概念.宏函数的特点是内嵌到调用代码中去,避免了函数调用 的开销.但是由于宏函数的处理发生在预处理阶段,缺失了语法检测和有可能带来的语意差错. 1.内联函数基本概念 C++提供了 in ...

  7. 利用C语言中的函数指针实现c++中的虚函数

    C语言中的函数指针 #include<stdio.h> int fun1(int a) { return a*a; } int fun2(int a) { return a*a*a; } ...

  8. 被弃用的php函数以及用来替代的函数

    下面列举了部分被弃用的函数: call_user_method()(使用 call_user_func() 替代) call_user_method_array() (使用 call_user_fun ...

  9. 【C语言C++编程入门】程序的可读性和函数的调用!

    一个简单程序的结构 你已经看过一个具体的例子,下面可以了解一些 C程序的基本规则了. 程序由一个或多个函数组成,其中一定有一个名为 main()的函数.函数的描述由函数头和函数体组成.函数头包括预处理 ...

随机推荐

  1. ESB企业服务总线

    ESB是企业服务总线(Enterprise Service Bus)的缩写,是中间件技术与Web Service等技术结合的产物,也是SOA系统中的核心基础设施.ESB就是一个服务的中介,形成服务使用 ...

  2. 函数表达式(JavaScript高程笔记)

    函数声明 特点:函数声明提升(执行代码之前解析器会先读取函数声明,并使其在执行任何代码之前可用,意味着可以把函数声明放在调用语句之后) function functionName(arg0,arg1) ...

  3. python学习之老男孩python全栈第九期_day010知识点总结

    def qqxing(l = []): # 可变数据类型 l.append(1) print(l)qqxing() # [1]qqxing([]) # [1]qqxing() # [1, 1]qqxi ...

  4. JavaScript高级编程——Date类型

    JavaScript高级编程——Date类型 <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" ...

  5. idea中连接oracle数据库打包

    问题:在使用idea连接oracle数据时发现oracle.jdbc.OracleDriver引用这个包报错,找不到包.解决方法:在idea的terminal命令框中输入如下命令.我的jar包的位置在 ...

  6. vue Element-UI 分页使用(1)

    最近在使用Element-UI这套框架配合Vue来写前端页面.在用Element-UI来制作表格的时候,遇到了一些小问题,记录方便学习. 其中两个事件是关于切换当前页和切换显示的列表条数的.另外的属性 ...

  7. CCNA学习笔记(1) IOS操作系统 路由器 交换机 启动 自检 以及部分命令

    注意:以下内容是以思科为学习环境 IOS操作系统启动: 路由和交换机和个人电脑启动没有区别,都会发送新号表示启动状态,也会进入系统自检.只得注意的是:1.一长两短的响声是显卡报警. 2.一声长鸣是内存 ...

  8. flutter .g文件生成不了

    [SEVERE] Conflicting outputs were detected and the build is unable to prompt for permission to remov ...

  9. Android Studio引用自定义的framework.jar包

    1.在app/libs/目录下添加framework.jar包. 2.打开build->Edit Libraries and Dependencies,把libs/framework.jar放到 ...

  10. [Java] 用 Comparator 实现排序

    最近正好用到Comparator,发现能对不同类型的对象进行排序(当然排序依据还是基本类型),也不用自己实现排序算法,用起来很方便,所以简单记录一下. 本文地址:http://www.cnblogs. ...