首页 > 代码库 > 关于C gets,fgets,gets_s函数一些扩展
关于C gets,fgets,gets_s函数一些扩展
自己写的,第一位观众席肯定是留给自己的.
前言废话:
工作之后总是忘不了当初学C时的感觉,那种调试,改错,成功后喜悦.虽简单到麻木,但是那是真的有点喜欢.
估计同老剧本很像,没钱时,放弃了自己喜欢的,有钱时,又想回去找Ta.估计也想是我那朋友"网视悠悠"说的"人生的矛盾"
之一吧.随着自己学习的深入,从最初的M$的.Net开发,逐渐走向C开发.也解决了最初的语言问题.因为我本身就不是
一个纯粹的程序员.我以前学的是数学.一直瞧不起搞编程的.这么简单的活.就是在玩堆积木.算法说白了不就是数学中处理
一类问题的一种解法吗.但是最后还是被社会打败了,确实跟着编程走了,有钱.哈哈.笑自己的成熟,笑自己的伪善.笑自己的无知.
哈哈.最后笑一下自己的搞笑.
很久以前自以为自己早已看破,放下.随着感悟随着年龄的增长而增多.有点小明白了.看破的是已经看破的,放下的是已经放下的.
"夏虫不可语于冰,笃于时也;井蛙不可语于海,拘于虚也"形容自身很是恰当.算了,大道无为,何拘以心.有爱胜过天地.
开始正题:
对于C89中gets函数,出现的问题,我就不说了.在C99和C11中官方说已经删除了gets函数,但是还是可以用,而且编译器有警告.
当然这个警告也可以删除.我就不说怎么删除这个警告了.毕竟gets确实安全隐患,被人进行蠕虫攻击.在C99中推荐使用
1 | char * fgets ( char * restrict dst, int max, FILE * restrict stream); |
fgets使用也很简单,使用例子如下:
#include <stdio.h> int max=10; //下面指针也可以用restrict修饰,表示当前指针是访问当前对象的唯一方式 char *bufs=malloc(sizeof(char)*max); fgets(bufs,max,stdin);
但是fgets使用存在两个问题,一个是如果输入的字符过少它会包含‘\n‘字符到bufs中,显然不好.当输入字符过多,会留下
输入缓存遗留的问题.后将fgets改写成sgets解决了上面的两个问题,函数如下:
/* *原型:char *sgets(int max); *描述:安全的读取最多max-1个字符,最后的字符替换为‘\0‘,如果结尾是\n也会被替换为‘\0‘ *参数:int max,最多读取max-1个asii码字符 *返回:char *指针,指向刚才读取的字符. */ char *sgets(int max) { char *get_str=malloc(max); fgets(get_str,max,stdin); int index=strlen(get_str)-1;/*获取最后一个字符的位置*/ if(*(get_str+index)==‘\n‘) *(get_str+index)=‘\0‘; /* *清除缓存吧 */ if(index==max-2) while((index=getchar())!=‘\n‘&&index!=EOF) putchar(index); return get_str; }
这个函数问题是解决了,但是感觉就像为fgets加了层皮.不好,效率无法控制,准备采用getchar重写上面的方法.新的函数叫
qgets,速度希望更快点.代码如下:
/* *原型:char *qgets(int max); *描述:安全且速度快的读取最多max-1个字符,最后的字符替换为‘\0‘,如果结尾是\n也会被替换为‘\0‘ *参数:int max,最多读取max-1个asii码字符 *返回:char *指针,指向刚才读取的字符. */ char *qgets(int max) { int index=0,ch; char *get_str=malloc(max--); while((ch=getchar())!=‘\n‘&&ch!=EOF) { if(index<max) *(get_str+index++)=ch; } *(get_str+index)=‘\0‘; return get_str; }
这次存在if开销,当用户输入的字符过多时,我们仍然在if判断.为了效率准备改一下代码将其if开销去掉.新修改的代码如下:
/* *原型:char *new_qgets(int max); *描述:读取固定长度-1长度的字符串,并将其变为C字符串,且替换‘\n‘ *参数:int max,最多读取max-1个字节字符 *返回:char *指针,指向字符串的字符指针 */ char *new_qgets(int max) { int index=0,ch; char *str=malloc(max--); while((ch=getchar())!=‘\n‘&&ch!=EOF) { if(index>=max) break; *(str+index)=ch; } if(index>=max) while((ch=getchar())!=‘\n‘&&ch!=EOF) ; *(str+index)=‘\0‘; return str; }
这样的话,应该处理起来比fgets要好一点了,不用malloc了,不用担心输入缓存遗留问题了.使用起来也简单,例子如下:
/*需要用的头文件*/ #include <stdio.h> #include <stdlib.h> /*函数的声明*/ char *new_qgets(int max); /*调用的方式*/ int max=10; char *bufs=new_qgets(max);/*最多保存9个asii字符,最后的位置保存‘\0‘*/
现在上面解决了一部分问题.下面和大家聊聊C11中gets_s函数
char * gets_s(char *dst, rsize_t max);
这个函数有点‘神奇‘.假如上面max=10,你能输入最多的字符数是8.如果你输入的字符数超过了8,由于最后还要加个‘\n‘.故此时已经
9个字符,函数默认最后第max个字符为‘\0‘预留.故dst中保存的是你输入的字符加上换行‘\n‘.如果你输入的字符超过8(超过max-2)
那么,它不会去读取.返回NULL.说很难表达一个问题,需要读者亲自去尝试.当然gets_s神奇之处还有一些.如下:
讨论之前,我需要说一些题外话.因为用的是C11的一些新东西,需要有支持C11的编译器.比较流行的是GCC系列.但是我个人
比较喜欢简单纯粹的.因而在Window平台下,向大家介绍几个纯C的编译器.
第一个:LCC-Win32/64 这最早是云风大神在2000年推荐,主要用在win98上.目前最新版是4.0.传说其支持C99.
我也当时也这么认为,但是有一次我在调试一个稍微复杂点程序,出了次意外,我调试了四五个小时,发现出错代码
就是:
Student stu=(Student){‘ZhangSan‘,18,1};
它不报错,但是赋的值是一个随机值.不是完美支持C99的集合初始化功能.还有一个小问题是,LCC支持中文输入不太好,它是
将中文字符当成两个字节来处.相当于它总是将中文分成两半.还有复制全选都很难操作.优点就是编译速度极快.
第二个:Pelles C x86/x64这个是基于LCC-Win32/64中编译器开发的.界面仿照VC++.(题外话,不要用VC或VS去写C,否则你就废了,写的,语法也会呈现杂交态).