首页 > 代码库 > 关于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,否则你就废了,写的,语法也会呈现杂交态).