c 语言实现 atof() 函数

1. atof() 函数介绍

C 库函数 *double atof(const char str) 属于库函数 stdlib.h,把参数 str 所指向的字符串转换为一个浮点数。

具体操作为:

跳过字符串开始的空白符,识别数字,点好,或正负符号,开始扫描合法浮点表达形式,直到遇到非合法字符结束扫描。如果空白符后是非合法字符,结束扫描,不会扫描后面的数字。

浮点数的合法表达形式

参见:C Primer Plus ---- Chapter 3 ----Data and C ---- 基本数据类型

-1.56E+12
2.87e-3
3.14159
.2
4e16
.8E-5
100.

  • 正数的符号位可以省略,小数部分的小数点(2E5)或者指数部分可以省略(12.),但两者不能同时省略。
  • 小数的小数部分可以省略(3.E16)或者省略整数部分(.45E–6),但两者不能同时省略。
  • 小数部分和指数部分不能有空格。

测试自带 atof() 函数

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char *s_gets(char *s, int n)
{
  char *ret, *find;
  ret = fgets(s, n, stdin);
  if(ret)
  {
    find = strchr(s, '\n');
    if(find)
    {
      *find = '\0';
    }
    else
    while(getchar() != '\n')
    continue;
  }
  return ret;
}
int main()
{
  double n;
  char s[10];
  while(s_gets(s, 10) && s[0] != '\0')
  {
    n = atof(s);
    printf("string: %s, float: %f\n", s, n);
  }
  return 0;
}

结果:

 3.2s      
string:  3.2s, float: 3.200000
.4s
string: .4s, float: 0.400000
-e2
string: -e2, float: 0.000000
.e3
string: .e3, float: 0.000000
1.e3s
string: 1.e3s, float: 1000.000000
.3e+2s
string: .3e+2s, float: 30.000000
.0e3s
string: .0e3s, float: 0.000000
.2e-2s
string: .2e-2s, float: 0.002000

2. 实现 atof() 函数功能

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<ctype.h>
#define LEN 40
char *s_gets(char *s, int n);
double myatof(const char *s);
int main(void)
{
	char s[LEN];
	double num;
	puts("Enter strings, enter a newline to quit:");
	while(s_gets(s, LEN) && s[0] != '\0')
	{
		num = myatof(s);
		printf("String: %s, corrsponding number: %f.\n",s, num);
	}
	puts("Bye!");
	return 0;
}
char *s_gets(char *s, int n)
{
	char *ret, *find;
	ret = fgets(s, n, stdin);
	if(ret)
	{
		find = strchr(s, '\n');
		if(find)
			*find = '\0';
		else
			while(getchar() != '\n')
				continue;
	}
	return ret;
}
double myatof(const char *s)
{
	int sign, sign_e;//数值的符号,指数部分的符号
	int hasdot = 0;
	int hase = 0;
	double intpart = 0.0;//小数的整数部分
	double decpart = 0.0; //小数的小数部分
	int decdigit = 1; //小数的小数位数
	int exp = 0; //指数部分
	double ret;
	int i;
	//跳过开头的空格
	for (i = 0; isspace(s[i]); i++)
		;
	//判断符号,如有,跳过
	sign = (s[i] == '-') ? -1 : 1;
	if (s[i] == '-' || s[i] == '+')
		i++;
	//判断浮点数
	//第一部分:
	for (; s[i] != '\0'; i++)
	{
		if (isdigit(s[i])) //数字
			intpart = 10 * intpart + s[i] - '0';//计算小数的整数部分
		else if (s[i] == '.') //小数点
		{
			hasdot = 1;
			i++;
			break;
		}
		else if (s[i] == 'e' || s[i] == 'E') //科学计数符
		{
			hase = 1;
			i++;
			break;
		}
		else //非法字符
			return sign * intpart;
	}
	/*第一部分结束,有如下情况:
	1. 扫描数字知道非法字符或字符串结尾,2d 234
	2. 数字加小数点 2.
	3. 小数点 .
	4. 数字加科学计数符 3e
	5. 科学计数符 e   这种情况是非法表示,但最终计算的结果为0,
		因此可当作正常计算,不单独列出
	6. 非法字符, 直接退出
	*/

	//第二部分,接着上述情况扫描
	//能进入下面循环,排除遇到字符串结尾,非法字符
	//因此只能遇到点号或科学计数符
	for (; s[i] != '\0'; i++)
	{
		//第一种:.3 或 3.4,均为合法,计算小数的小数部分
		if (hasdot && isdigit(s[i]))
			decpart += (s[i] - '0') / pow(10, decdigit++);
		//第二种:.e 或 2.e 或 .2e 或 3.3e 第一种非法,但计算结果为0
		else if (hasdot && (s[i] == 'e' || s[i] == 'E'))
		{
			hase = 1;
			i++;
			break;
		}
		//第三种:第一部分以e结束,3e e
		else if (hase)
			break;
		//第四种:第一部分以点号结束,现在扫描非数字,非科学计数符的其他非法字符
		else
			return sign * (intpart + decpart);
	}
	/*第三部分
	从第二部分退出后继续后面的程序,有如下情况:
	以科学计算符 e 结束第二部分,前面有小数点或者没有
	小数部分计算完,下面讨论指数部分
	*/
	//判断指数部分符号
	sign_e = (s[i] == '-') ? -1 : 1;
	if (s[i] == '+' || s[i] == '-')
		i++;
	for(; s[i] != '\0'; i++)
	{
		if(isdigit(s[i]))
			exp = exp * 10 + s[i] - '0';
		else
			break;
	}
	ret = sign * ((intpart + decpart) * pow(10, sign_e * exp));
	return ret;
}
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值