【C语言】模拟实现atoi函数

  atoi(表示 ascii to integer)是把字符串转换成整型数的一个函数.

  atoi()函数会扫描参数 nptr字符串,跳过前面的空白字符(例如空格,tab缩进等,可以通过isspace( )函数来检测),直到遇上数字或正负符号才开始做转换,而再遇到非数字或字符串结束时('\0')才结束转换,并将结果返回。如果 nptr不能转换成 int 或者 nptr为空字符串,那么将返回0

  我们在模拟实现atoi函数时,要注意以下几点:

  1.字符串之前的空白问题  

  2.正负号

  3.字符串为空时

  4.被转换的数字过于大(正溢出、负溢出)

  5.其他,无法转换的情况(全是字母....之类的)

  我们了解atoi函数功能和一些注意事项之后,开始模拟实现它,代码如下:

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
enum{
	vaild = 0,
	invaild = 1
};
int flag = vaild;
int my_atoi(const char *str){
	long long ret = 0;
	int symbol = 1;
	//断言str!=NULL
	assert(str);
	//判断空字符
	if( '\0' == *str ){
		flag = invaild;
		return 0;
	}
	//去掉空格、制表符
	while(isspace(*str)){
		str++;
	}
	//符号位判断
	if('-'==*str){
		symbol = -1;
		str++;
	}else if('+'==*str){
		str++;
	}else if(((*str<='0')&&(*str>='9'))){
		flag = invaild;
		return 0;
	}
	//其他异常情况处理完毕,开始转换
	while((*str!='\0')&&(*str>='0')&&(*str<='9')){
		ret = (ret*10 + *str-'0');
		str++;
	}
	//带上符号位
	ret *= symbol;
	//检测溢出
	//int 0111 1111 1111 1111 1111 1111 1111 1111 正溢出
	//     7    f    f    f    f    f    f    f
	//    1000 0000 0000 0000 0000 0000 0000 0000 负溢出
	//      8     0   0   0     0    0    0    0
	if(((ret>0x7fffffff)&&(1==symbol)) ||
	(ret<(signed int)0x80000000)&&(-1==symbol)){
		flag = invaild;
		return 0;
	}
	//ret合法
	flag = vaild;
	return ret;
}
//打印atoi函数状态+\n
void PrintState(){
	if(flag){
		printf("异常\n");
	}else{
		printf("正常\n");
	}
}
//测试函数
void FunTest(){
	printf("value=%d,state=",my_atoi("123456789"));
	PrintState();//正常
	printf("value=%d,state=",my_atoi("-123456789"));
	PrintState();//正常
	printf("value=%d,state=",my_atoi("-123456789sassa"));
	PrintState();//正常,遇到字母终止
	printf("value=%d,state=",my_atoi("	  -123456789sassa"));
	PrintState();//正常,前面带空格
	printf("value=%d,state=",my_atoi(""));
	//////////////异常情况/////////
	printf("\n\n");
	PrintState();//异常:空字符串
	printf("value=%d,state=",my_atoi("123456789123456789"),flag);
	PrintState();//异常:正溢出
	printf("value=%d,state=",my_atoi("-123456789123456789"),flag);
	PrintState();//异常:负溢出
	printf("value=%d,state=",my_atoi("dasdsa"),flag);
	PrintState();//异常:无法转换
}
int main(){
	FunTest();
	return 0;
}

  彩蛋:在写测试函数时,有一件事,始终不得其解,一开始我将测试代码写成了这样:

void FunTest(){
	printf("value=%d,state=%d\n",my_atoi("123456789"),flag);//正常
	printf("value=%d,state=%d\n",my_atoi("-123456789"),flag);//正常
	printf("value=%d,state=%d\n",my_atoi("-123456789sassa"),flag);//正常,遇到字母终止
	printf("value=%d,state=%d\n",my_atoi("	  -123456789sassa"),flag);//正常,前面带空格
	printf("\n\n\n");
	printf("value=%d,state=%d\n",my_atoi(""),flag);//异常:空字符串
	printf("value=%d,state=%d\n",my_atoi("123456789123456789"),flag);//异常:正溢出
	printf("value=%d,state=%d\n",my_atoi("-123456789123456789"),flag);//异常:负溢出
	printf("value=%d,state=%d\n",my_atoi("dasdsa"),flag);//异常:无法转换
}

  测试时,发现一件诡异的事情!!!!!!!

  结果输出是这样:

value=123456789,state=0
value=-123456789,state=0
value=-123456789,state=0
value=-123456789,state=0


value=0,state=0    //卧槽!!!为什么是0?
value=0,state=1
value=0,state=1
value=0,state=1

  我还特意跟进函数体内看,发现全局变量flag确实被改为了1,但为什么输出的是0呢???

  正当我百思不得其解时,突然想到printf函数的调用约定是_cdel!!!!

  因此,_cdel调用约定,是将参数由右向左压栈,因此它先将flag压栈,然后再执行my_atoi函数,在my_atoi函数体内修改了全局变量flag.....

  所以,最终输出了0!

  因此,才有了最终代码!

  

posted @ 2016-11-17 22:31  C/C++专题  阅读(1861)  评论(1编辑  收藏  举报