实现string到double的转换

时间:2021-03-28 14:56:29

分析:此题虽然类似于atoi函数,但毕竟double为64位, 而且支持小数,因而边界条件更加严格,写代码时需要更加注意。

#include <errno.h>
#include <float.h>
#include <stdio.h>
#include <stdlib.h>
#include "math.h"

enum status {
	invaild = 0, vaild
};
int g_status = vaild;

int isspace(const char* str) {
	return *str == ' ';
}

int isDigit(char num) {
	if (num >= '0' && num <= '9') {
		return 1;
	} else {
		return 0;
	}
}

//对atof函数进行扩充,使其可以处理科学计数法形式的字符如 123.45e-6
double strToDouble(const char* nptr) {

	double val = 0, power = 1;
	int exp = 0;

	if (nptr == NULL) {
		return 0;
	}
	g_status = invaild;
	//跳过空格
	while (*nptr == ' ') {
		nptr++;
	}

	int flag = *nptr == '-' ? -1 : 1;
	if (*nptr == '-' || *nptr == '+') {
		nptr++;
	}

	while (isDigit(*nptr)) {
		val = val * 10 + *(nptr++) - '0';
	}

	if (*nptr == '.') {
		nptr++;
	}

	while (isDigit(*nptr)) {
		val = val * 10 + *(nptr++) - '0';
		power *= 10;
	}

	val = val / power;

	if (*nptr == 'e' || *nptr == 'E') {
		nptr++;
		int eflag = *nptr == '-' ? -1 : 1;
		if (*nptr == '-' || *nptr == '+') {
			nptr++;
		}
		while (isDigit(*nptr)) {
			exp = exp * 10 + *(nptr++) - '0';
		}

		//是否越界
//		 else

		if (eflag == 1) {
			if (val > DBL_MAX * pow(10.0, (double) -exp)) {
				return DBL_MAX;
			}
			while (exp-- > 0) {
				val *= 10;
			}
		} else if (eflag == -1) {
			if (val < DBL_MIN * pow(10.0, (double) exp)) {

				return DBL_MIN;
			}
			while (exp-- > 0) {
				val /= 10;
			}
		}
	}

	if (*nptr == '\0') {
		g_status = vaild;
	}
	return flag * val;

}

int main(void) {
//	DBL_MIN: 2.2250738585072014e-308
//	DBL_MAX: 1.7976931348623157e+308
	setvbuf(stdout, NULL, _IONBF, 0);
	char str[100] = "1.79e308";
	double num;
	num = strToDouble(str);
	if (g_status) {
		printf("%.16e\n", num);
	} else {
		printf("%s", "invaild input!!!");
	}

	return EXIT_SUCCESS;
}