c语言gets()函数与它的替代者fgets()函数

在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也会将换行符读入。

时间: 2024-10-13 21:02:15

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

[Go语言]从Docker源码学习Go——结构和函数的定义

Docker在最近很火,而作为Docker的开发语言-Go也再次被大家提到. 已经使用Docker一段时间了,但是对于源码,尤其是其开发语言Go却一直是一知半解. 最近准备利用空余时间从Docker源代码入手来学习一下Go,同时对Docker的实现也希望可以提高一个层次. 有兴趣的可以一起讨论,学习. 准备工作: 1. Docker源代码https://github.com/docker/docker (版本1.1.2) 2. 安装开发工具LiteIDE, 这个是官方的Go语言的IDE 3. G

【C语言天天练(四)】可变参数函数

可变参数函数指可以接受可变数量参数的函数.比如printf函数就是一个可变参数函数. 要完成可变参数函数的编写,需要用到定义于stdarg.h头文件中的一个类型va_list和三个宏va_start.va_arg.va_end. 注意: 1.可变参数必须从头到尾按照顺序逐个访问.如果在访问几个可变参数后想半途中止,这是可以的.但是,如果想一开始就访问列表中的参数,那是不行的. 2.由于参数列表中的可变参数部分并没有原型,所以,所有作为可变参数传递给函数的值都将执行缺省参数类型提升. 3.参数列表

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

下面列举了部分被弃用的函数: call_user_method()(使用 call_user_func() 替代) call_user_method_array() (使用 call_user_func_array() 替代) define_syslog_variables() dl() ereg() (使用 preg_match() 替代) ereg_replace() (使用 preg_replace() 替代) eregi() (使用 preg_match() 配合 'i' 修正符替代)

C语言基础学习7:返回指针值的函数

一个函数可以返回一个整型值.字符值.实型值等,也可以返回指针型的数据,即地址,返回的是指针类型. 返回指针值的函数的一般定义形式为; 数据类型 *函数名(参数列表) 例如: int *a(int x, int y); a作为函数名,调用它之后能得到一个指向整型数据的指针(地址). ()优先级高于*,因此a先与()结合,这是函数形式,返回值为指针形式. 1 #include <stdio.h> 2 float *search(float (*pointer)[4]); 3 float *sear

【C语言天天练(二十)】scanf函数详解

引言:scanf函数虽然是学习C语言时比较早就接触的一个函数,但在使用过程中,发现真正掌握它却并不容易.本文就通过各种例子来详细的总结一下该函数的各种用法,假设它的调用格式为 scanf("<格式化字符串>",<地址表>). 1.一般使用scanf函数时都是为某个变量赋值,不考虑它的返回值.但是任何函数都是需要返回的(即使返回类型用void,也可以认为只是调用了return语句,只是并没有返回什么东西而已),同样的scanf函数也是有返回的,它的返回值是成功读取

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

C语言常用的库文件(头文件.函数库) C系统提供了丰富的系统文件,称为库文件.C的库文件分为两类,一类是扩展名为".h"的文件,称为头文件,在前面的包含命令中我们已多次使用过.在".h"文件中包含了常量定义. 类型定义.宏定义.函数原型以及各种编译选择设置等信息.另一类是函数库,包括了各种函数的目标代码,供用户在程序中调用.通常在程序中调用一个库函数时,要在调用之前包含该函数原型所在的".h" 文件. 下面给出Turbo C的全部".h

C语言文件的读入与写入及C#基础函数学习[图]

C语言文件的读入与写入及C#基础函数学习[图]学了一学期的C语言,还不怎么会使用指针,文件的读入和写入也不能很顺利的写出来,说起来好惭愧.碰巧今天朋友让我帮他编写一个C语言程序,对他数模要用到的大量数据求平均值(每天不同时刻对某一物理量进行检测,持续几十天,求那些时刻测得的物理量的平均值).代码很简单,关键是要掌握怎样对文件进行读入和写入(当然对于菜鸡的我来说,懒惰让我在大一没有好好学习,正好趁着这个契机把文件的基本的操作学会:))分模块来编写还是很重要的,可以使程序看起来简洁明了.写了两个函数

C语言--- 高级指针2(结构体指针,数组作为函数参数)

一.结构体指针 1. 什么是结构体指针?指向结构体变量的指针     结构体:     typedef  struct stu{                          char name[20];                          char sex;                          int age;                    }Student;     Student stu1 = {"zhangsan",'m',23};  

C语言gets函数,fgets函数的使用

gets从标准输入设备读字符串函数.可以无限读取,不会判断上限,以回车结束读取.函数的具体功能如下所示:从stdin流中读取字符串,直至接受到换行符或EOF时停止,并将读取的结果存放在buffer指针所指向的字符数组中.换行符不作为读取串的内容,读取的换行符被转换为‘\0’空字符,并由此来结束字符串. 使用gets函数的时候应注意以下要素:可以无限读取,不会判断上限,所以程序员应该确保buffer的空间足够大,以便在执行读操作时不发生溢出.如果溢出,多出来的字符将被写入到堆栈中,破坏一个或多个不