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

以上所述是小编给大家介绍的详解C语言gets()函数与它的替代者fgets()函数的相关知识,希望对大家有所帮助,如果大家想了解更多,敬请关注我们!

(0)

相关推荐

  • C语言文件操作中 fgets与fputs 函数详解

    C语言文件操作中 fgets.fputs 函数详解 先给出api fgets 语法: #include <stdio.h> char *fgets( char *str, int num, FILE *stream ); 函数fgets()从给出的文件流中读取[num - 1]个字符并且把它们转储到str(字符串)中. fgets()在到达行末时停止,在这种情况下,str(字符串)将会被一个新行符结束. 如果fgets()达到[num - 1]个字符或者遇到EOF, str(字符串)将会以nu

  • C语言中fgets和fscanf区别详解

    C语言中fgets和fscanf区别详解 一.作用上的大概区别: ①fgets:从文件中读取一行数据存入缓冲区(fgets遇到回车才会结束,不对空格和回车做任何转换就录入到缓冲区,结束后再往缓冲区写多一个\0,所以它是读一行数据) ②fscanf:从文件中读取一段数据存入缓冲区(fscanf遇到空格或回车就结束,它会把空格或回车转换为\0,所以它是读一小段数据) 二.举个例子:把a.txt文件中的内容复制到b.txt. a.txt中的内容(第一行中"我爱你小白"和"开玩笑&q

  • 详解C语言gets()函数与它的替代者fgets()函数

    在c语言中读取字符串有多种方法,比如scanf() 配合%s使用,但是这种方法只能获取一个单词,即遇到空格等空字符就会返回.如果要读取一行字符串,比如: I love BIT 这种情况,scanf()就无能为力了.这时我们最先想到的是用gets()读取. gets()函数从标准输入(键盘)读入一行数据,所谓读取一行,就是遇到换行符就返回.gets()函数并不读取换行符'\n',它会吧换行符替换成空字符'\0',作为c语言字符串结束的标志. gets()函数经常和puts()函数配对使用,puts

  • 详解C语言函数返回值解析

    详解C语言函数返回值解析 程序一: int main() { int *p; int i; int*fun(void); p=fun(); for(i=0;i<3;i++) { printf("%d\n",*p); p++; } return 0; }; int* fun(void) { static int str[]={1,2,3,4,5}; int*q=str; return q; } //不能正确返回 虽然str是在动态变量区,而该动态变量是局部的,函数结束时不保留的.

  • 详解C语言用malloc函数申请二维动态数组的实例

    详解C语言用malloc函数申请二维动态数组的实例 C语言在程序运行中动态的申请及释放内存十分方便,一维数组的申请及释放比较简单. Sample one #include <stdio.h> int main() { char * p=(char *)malloc(sizeof(char)*5);//申请包含5个字符型的数组 free(p); return 0; } 是否申请二维动态内存也如此简单呢?答案是否定的.申请二维数组有一下几种方法 Sample two /* 申请一个5行3列的字符型

  • 详解C语言常用的一些转换工具函数

    1.字符串转十六进制 代码实现: 2.十六进制转字符串 代码实现: 或者 效果:十六进制:0x13 0xAA 0x02转为字符串:"13AAA2" 3.字符串转十进制 代码实现: 第一种,如果带负号 这个就是atoi函数的实现: 效果:字符串:"-123" 转为 -123 第二种,如果不带负号: 效果:字符串:"123" 转为 123 第三种:包含转为浮点数: 效果:字符串:"123.456" 先转为 123456,然后除以1

  • 详解Go语言Slice作为函数参数的使用

    目录 前言 问题与解析 典型问题 其它疑问1 其它疑问2 结论 参考链接 前言 首先要明确Go语言中实质只有值传递,引用传递和指针传递是相对于参数类型来说. 个人认为上诉的结论不对,把引用类型看做对指针的封装,一般封装为结构体,结构体是值类型,所以感觉都是值传递.不然我感觉其它语言实质不也都是值传递?不过我刚学Go,可能还没完全弄懂,这个有问题可以互相讨论下. Go语言中的值类型:int.float.bool.array.sturct等,声明一个值类型变量时,编译器会在栈中分配一个空间,空间里存

  • 详解C语言fscanf函数读取文件教程及源码

    目录 第一部分:问题和结论 fscanf 函数的原型是: 第二部分:实验代码 实验代码: fscanf 函数用于格式化读入文件中数据,可以大大提高读取文件的效率.这次笔者将最近使用该函数的一些经验记录下来. 第一部分:问题和结论 fscanf 函数的原型是: int fscanf(FILE* stream, const char* format, [argument...]); fscanf 函数与 scanf 函数用法类似,只不过前者用于读取文件流的数据而已.至于 fscanf 的基础用法我就

  • 详解Go语言如何实现字符串切片反转函数

    目录 Python 中的 reverse 函数 实现一个 reverse 反转函数 利用两个切片实现 前后两两原地交换 反转为原切片的副本 总结 Python 中的 reverse 函数 Go 语言不像其他语言如 Python,有着内置的 reverse() 函数,先来看一下 Python 中对于列表的反转方法,然后我们再来学习如果在 Go 语言中实现相同的功能. >>> myList = [2022, 2021, 2008, 2012] >>> myList.reve

  • 详解Go语言strconv与其他基本数据类型转换函数的使用

    目录 前言 strconv string 与 int 之间的转换 Itoa:int 类型转 string 类型 Atoi:string 类型转 int 类型 FormatInt:将数字转成指定进制数并以 string 类型返回 ParseInt:给定基数(进制数)和位数,返回对应十进制的值 string 与 float 之间的转换 ParseFloat:字符串类型转浮点型类型 FormatFloat:根据格式 fmt 和精度 prec 将浮点数 f 转换为字符串 string 与 bool 之间

  • 详解Go语言如何利用高阶函数写出优雅的代码

    目录 前言 问题 白银 黄金 王者 总结 前言 go项目中经常需要查询db,按照以前java开发经验,会根据查询条件写很多方法,如: GetUserByUserID GetUsersByName GetUsersByAge 每一种查询条件写一个方法,这种方式对外是挺好的,对外遵循严格原则,让每个对外的方法接口是明确的.但是对内的话,应该尽可能的通用,做到代码复用,少写代码,让代码看起来更优雅.整洁. 问题 在review代码的时候,针对上面3个方法,一般写法是 func GetUserByUse

  • 详解C语言 三大循环 四大跳转 和判断语句

    三大循环for while 和 do{ }while; 四大跳转 : 无条件跳转语句 go to; 跳出循环语句 break; 继续跳出循环语句 continue; 返回值语句 return 判断语句 if,if else,if else if else if...else ifelse 组合 if(0 == x) if(0 == y) error(): else{ //program code } else到底与那个if配对 C语言有这样的规定: else 始终与同一括号内最近的未匹配的if语

随机推荐