zoukankan      html  css  js  c++  java
  • linux下使用fscanf实现scanf


              首先,我们知道,linux下的scanf标准库函数是一个可变参的函数,那么,我们自己要实现一个scanf也必须是一个可变参的.

    其实,在liunx的库中就提供了这样的的宏,来方便我们自己来实现变参函数.这个宏在stdarg.h头文件中.

    这几个宏如下:

        void va_start( va_list   arg_ptr, prev_param ); //va_start宏初始化变量arg_ptr,这个宏的第二个参数是第 一个可变参数的前一个参数,是一个固定的参数.

       type va_arg( va_list   arg_ptr, type ); //a_arg返回可变的参数, va_arg的第二个 参数是你要返回的参数的类型,

       void va_end( va_list   arg_ptr ); //va_end宏结束可变参数的获取,
       va在这里是variable-argument(可变参数)的意思.

    这几个宏的具体使用方法,百度上也有很多,不过为了方便这也给出了一个介绍其使用的博客:点击打开链接

         好了,下面就是我写的用fscanf来实现scanf的程序,如有不对之处,敬请指出...

    /*************************************************************************
        > File Name: scanf.c
        > Author: yexingkong
        > Mail: abqyexingkong@gmail.com
        > Created Time: Wed 04 Sep 2013 16:23:17 CST
        > Description:用fscanf() 模拟scanf,此函数的不足之处在于对于flaot类型数的精确度不够,还未想到更好的解决方法.
     ************************************************************************/
    
    #include <stdio.h>
    #include <stdarg.h>
    #include <stdlib.h>
    #include <ctype.h>
    #include <stdint.h>
    
    
    
    //检测所输入的字符串str是否全为空格,若是,则重新输入,这也是scanf是I/O阻塞型的原因.
    static uint8_t scan_skip(char *str, uint8_t i)
    {
        FILE *fp;
    
    
        fp = fdopen(0,"r");
    
        if (fp == NULL)
        {
            perror("error
    ");
            exit(EXIT_FAILURE);
        }
    
        loop:
        //isspace检测所输入的字符是否为空格,返回空格数.
        while(isspace(str[i]))
        {
            i++;
        }
        //如果一直到字符串结束都是空格,则重新输入
        if (str[i] == 0)
        {
            i = 0;
            fscanf(fp,"%[^'
    ']",str);
            goto loop;
        }
    
        //返回第一个非空格字符的下标
        return i;
    }
    
    //如果以%d/%u格式读取数,则对其字符串str中的数字字符转成base进制的数.
    //参数base 是进行进制转换的基数,*nb用来保存所转换后的结果.(eg: base= 8则为八
    //进制数)
    static uint8_t scan_int(char *str,uint8_t i, uint8_t base,int8_t *nb)
    {
        int8_t n = 0;
        uint8_t j,sign = 0;
    
        //检测此十进制数的正,负性
        switch(str[i])
        {
            case '-':
                sign = 1;
            case '+':
                i++;
            break;
        }
    
        while(1)
        {
            if (isdigit(str[i]))    //判断是否为数字'0' ~ '9'
            {
                j = str[i] - '0';
            }else if (isalpha(str[i])) //判断是否为字母
            {
                j = toupper(str[i]) - 'A' + 10; //用来计算16进制数
            }
            else
                break;
            if (j >= base)
                break;
    
             n = base * n + j;   //将字符转换成base进制的数
                i++;
        }
        *nb = (sign == 0 ? n: -n);  //正负数的判读
    
        //返回当前已读到的最后一个字符的下标
        return i;
    }
    
    //以长整型格式输入,则对其字符串str中的数字字符转成base进制的数,
    //i为当前所要读取的字符的下标,*nb用来保存所转换后的结果.
    static uint8_t scan_long(char *str,uint8_t i,uint8_t base,int16_t *nb)
    {
        int16_t n = 0;
        uint8_t j,sign = 0;
    
        //对所读取的正负性判断
        switch (str[i])
        {
            case '-':
                sign = 1;
            case '+':
                i++;
                break;
        }
    
    
        while (1)
        {
            if (isdigit(str[i])) //判断是否为数字
            {
                j = str[i] - '0';
            }else if (isalpha(str[i])) //判断是否为字母
            {
                j = toupper(str[i]) - 'A' + 10;  //用来计算16进制的数
            }else
                break;
            if (j >= base)
                break;
    
            n = n * base + j;
                i++;
        }
        *nb = (sign == 0? n: -n); //对正负数的判读
    
        //返回当前已读到的最后一个字符的下标
        return i;
    
    }
    
    
    static uint8_t scan_float(char *str,uint8_t i,uint8_t base,float *nb)
    {
        float n = 0.0, j, m = 0;
        uint8_t sign = 0;
        int flag = 0 , k =0;
    
    
        switch (str[i])
        {
            case '-':
                sign = 1;
            case '+':
                i++;
                break;
        }
    
        while (1)
        {
            //计算整数部分
            if (isdigit(str[i]) && flag == 0)
            {
                j = str[i] - '0';
                n = base * n + j;
            } else if (str[i] == '.')
            {
                flag = 1;   //作为标记符
                i++;
                continue;
            }else if (isdigit(str[i]) && flag == 1)     //计算小数部分
            {
                j = str[i] - '0';
                m = base * m + j;
    
                k++; //计算小数点位数
                if (k > 5)
                    break;
            }else
                break;
    
            i++;
        }
    
        //将小数点六位后的数字忽略掉
        while(1)
        {
            if (isdigit(str[i]))
            {
            i++;
                continue;
            }else
                break;
        }
    switch (k)
    {
        case 1:
            n = n + m * 1e-1;
                break;
        case 2:
            n = n + m * 1e-2;
                break;
        case 3:
            n = n + m * 1e-3;
                break;
        case 4:
            n = n + m * 1e-4;
                break;
        case 5:
            n = n + m * 1e-5;
                break;
        default:
            n = n + m * 1e-6;
                break;
    }
    
        *nb = (sign == 0? n : -n);
    
        return i;
    
    }
    
    
    int8_t myscanf(const char *format , ...)
    {
        //定义一个指向形参列表的指针pArg
        va_list pArg;
        char str[64];
        uint8_t i = 0;
        int8_t nb = 0; //记录参数个数
    
        FILE *fp;
    
    
    
        fp = fdopen(0,"r");
    
        if (NULL == fp)
        {
            perror("error
    ");
            exit(EXIT_FAILURE);
        }
    
        fscanf(fp,"%[^'
    ']",str);
    
        printf("iput=%s
    ",str);
    
        va_start(pArg,format);//让pArg指向函数参数列表中的最后一个明确的参数,这里就是format参数.
    
    
        for(;*format != 0; format++)
        {
    
         if (isspace(*format))
                continue;
            //找到所输入的字符串中第一个非空格字符的下标,或I/O阻塞,从新输入
            i = scan_skip(str,i);
    
    
            if (*format == '%')
            {
            switch(*(++format))
            {
                case 'c':
                /* char */
                    *va_arg(pArg,char *) = str[i++]; //给pArg所指向的地址空间单元赋值
                    break;
                case 'd':
                    /* decimal int */
                case 'u':
                    /* unsigned int */
                i = scan_int(str,i,10,va_arg(pArg,int8_t *));  //va_arg()用来返回pArg所指向的地址单元中的值
                    break;
                case 'f':
                i = scan_float(str,i,10,va_arg(pArg,float *));
                    break;
                case 'o':
                i = scan_int(str,i,8,va_arg(pArg,int8_t *));
                    break;
                case 'x':
                i = scan_int(str,i,16,va_arg(pArg,int8_t *));
                    break;
                case 's':
                {
                    int8_t j = 0;
                    char *d = va_arg(pArg,char *);
                    while ((d[j++] = str[i++]) != 0)
                        ;
                }
                    break;
                /* long */
                case 'l':
                     switch (*(++format))
                    {
                        case 'd':
                         /*decimal long */
                        case 'u':
                         i = scan_long(str,i,10,va_arg(pArg,int16_t *));
                             break;
                        case 'o':
                        i = scan_long(str,i,8,va_arg(pArg,int16_t *));
                             break;
                        case 'x':
                        i = scan_long(str,i,16,va_arg(pArg,int16_t *));
                             break;
                     }
                break;
                default:
                    if (str[i] != *format)
                         return -1;
                break;
            }
            nb++;
        }else if (str[i] != *format)
            return -1;
        }
    
    //使pArg不再指向堆栈,结束对形参的取值
        va_end(pArg);
    
    //返回参数个数
        return nb;
    }
    
    
    
    
    int main(int argc,char *argv[]){
    
        int d = 0;
        char c ='';
        float f = 0.0;
        char str[10];
        int se;
    
        printf("输入char float  char[]型的数
    ");
    
        myscanf("%c %f %s",&c,&f,str);
        printf("%c	%f	%s
    ",c,f,str);
           return 0;
    }

    转载请注明出处:http://write.blog.csdn.net/postedit/12451273


  • 相关阅读:
    E
    CSU 1757 火车进站 1757
    [Unity游戏开发]场景切换
    相机跟随
    [Unity游戏开发]Vector3类
    [Unity游戏开发] 关于向量计算的一些基础
    [Unity游戏开发] MonoBehaviour类常用方法(脚本生命周期)
    C#学习笔记之——new在哪些地方用
    C#——快速排序
    C#学习笔记之——事件(Event)
  • 原文地址:https://www.cnblogs.com/pangblog/p/3359914.html
Copyright © 2011-2022 走看看