文章主要介绍atoi的模拟实现,包含具体实现思路以及代码讲解;同时,对MSDN中atoi的作用进行了仔细介绍。 注:第一部分是在MSDN中的注解,第二部分包含笔者对函数的分析以及具体实现,第三部分则是笔者对于此模拟实现的一些缺陷说明。

一、atoi在MSDN中的注解

image.pngatoi函数将字符串转换为整型;

1、返回值

image.png当字符串可以转换为整型时,函数会返回一个整型的值(对于atoi); 不可以转换时,会返回0; 若产生溢出,返回值未定义,也就是说:数据溢出的话,atoi的处理会出错;

2、参数

image.png需要转换的字符串;

3、标注

image.png函数会将字符串转换为特定类型的数据,然后返回;在第一个字符未识别到数字时,函数会停止识别;用来识别的字符串可以是用于终止字符串的空字符\0;

二、具体实现

1、原函数测试

分析:

通过在MSDN中函数的描述,我们对atoi已经有了大概想法:

  • 函数将字符串转换为整型数据,然后返回;
  • 在识别第一个字符时,若遇到非数字,则会停止转换数据;
  • 转换成功时,返回转换值,失败则返回0;
  • 对于数据溢出的情况,atoi没有明确规定;
思考:

做了上述分析,但有些情况我们并不清楚,比如说:

  • 函数遇到空指针;
  • 函数第一个字符为+号或-号;
  • 函数遇到空白;
  • 字符串中同时存在数字与非数字的识别情况;
测试
  • 首先,遇到空指针时: image.png函数报错,故我们应限制,不可输入NULL;  

  • 遇到+号或-号时: image.png-号会返回负值; image.png+号返回正值; 也就是说,atoi函数的识别会包括 + - 符号;  

  • 遇到空白时: image.png函数会跳过空白字符,而在空白字符后的第一个字符开始转换;

  • 字符串同时存在数字与非数字: 非数字位于数字中: image.png函数在遇到非数字时停止转换; 数字位于非数字中:image.png函数未进行转换,便返回0; 数字中包含\0时: image.png由此可知:‘\0’也仅作为非数字字符串的一种,与非数字的处理相同;

2、实现

根据上述分析,已经清楚: atoi函数具有以下特点

  • 遇到非数字字符,停止识别,遇到数字字符,逐个识别为整型值; 定义内置compute函数,每识别一个字符,加到个位,同时原数据×10;
int compute(const char* s)
{
	int ret = 0;
	while (isdigit(*s))
	{
		ret = ret * 10 + (*s++ - '0');
	}
	return ret;
}
  • 遇到空白会跳过; 由于空白的字符表示是‘\t’,因此只需循环跳过字符串开始的空白即可;
while ((*s++) == '\t');
  • 只在除去空白后的第一个位置识别正负符号; 正负号的判断在第一个位置执行,因此只需一次if语句,判断即可;
	if (isdigit(*s))
	{
		ret = compute(s);
	}
	else if (*s == '-')
	{
		ret = -compute(s + 1);
	}
	else if (*s == '+')
	{
		ret = compute(s + 1);
	}
	else
	{
		return 0;
	}
  • 存在边界问题,数据溢出返回值无法预测; 此处笔者暂时未想到合适的方法判断数据溢出,在上述的实现中,若存在数据溢出,则返回值不可靠;  

三、模拟实现

总代码:

由具体分析实现代码如下:

//计算转换字符值
int compute(const char* s)
{
	int ret = 0;
	while (isdigit(*s))
	{
		ret = ret * 10 + (*s++ - '0');
	}
	return ret;
}
int my_atoi(const char* s)
{
	//判空
	assert(s);
	int ret = 0;
	//跳过空白
	while ((*s++) == '\t');
	//判别第一个字符
	if (isdigit(*s) || *s == '+')
	{
		ret = compute(s);
	}
	else if (*s == '-')
	{
		ret = -compute(s + 1);
	}
	else
	{
		return 0;
	}
	return ret;
}

缺陷:

  • 无法判断数据是否溢出; 当数据超过int可表示的最大值时(也就是除符号位外全为1): image.png 则会将后续的1顶到符号位上,从而造成数据的不准确。