linux fscanf,linux fscanf

场景:linux停使用fscanf实现scanf

linux下使用fscanf实现scanf

104135644.jpg

首先,我们知道,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

#include

#include

#include

#include

//检测所输入的字符串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\n");

exit(EXIT_FAILURE);

}

loop:

//isspace检测所输入的字符是否为空格,返回空格数.

while(isspace(str[i]))

{

i++;

}

//如果一直到字符串结束都是空格,则重新输入

if (str[i] == 0)

{

i = 0;

fscanf(fp,"%[^'\n']",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\n");

exit(EXIT_FAILURE);

}

fscanf(fp,"%[^'\n']",str);

printf("iput=%s\n",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 ='\0';

float f = 0.0;

char str[10];

int se;

printf("输入char float char[]型的数\n");

myscanf("%c %f %s",&c,&f,str);

printf("%c\t%f\t%s\n",c,f,str);

return 0;

}

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值