一个健壮性良好的atoi函数的实现

一个健壮性良好的atoi函数的实现

1 函数说明

C89中的说明:

  头文件

  stdlib.h

  函数原型

  intatoi(const char *nptr);

  nptr:指向待转换的字符串的指针

  返回值

  字串的整型形式, 必须以NULL结尾.

  说明

  atoi函数跳过字串开头的所有空白字符, 转换接下来的数字字符, 遇到第一个非数字字符停止

 

C11的标准中关于atoi的描述为:

  当遇到错误时, atoi不需要改变errno的值, 当值的结果无法表示时, 行为是未定义的.

  除了错误处理外, 它等价于(equivalent): (int)strtol(nptr, (char**)NULL, 10)

2  函数黑盒测试

  根据函数说明,确定边界条件,编写测试用例如下:

一个健壮性良好的atoi函数的实现_第1张图片

一个健壮性良好的atoi函数的实现_第2张图片


从以上数据, 可以分析出以下几点:

  (1) 空字串("")或非法字串(如"abc"), 输出0;

  (2) 可以有符号(如"123"),也可以没有(如"-123"), 如果有符号, 则符号后面必须是数字, 符号与数字之间不能有空格;

  (3) 开头的空格将被过滤, 末尾的空格也不会管;

  (4) 数字前面的字符'0'将被过滤(如"010");

  (5) 如果超过最大值(如"2147483648"),则输出最大值2147483647(32位的最大int值); 如果超过最小值         (如"-2147483649"),则输出最小值-2147483648(32位的最小int值);

  (6)  不只是空格, 开头和末尾的所有空白字符(isspace)都将被过滤;

  (7)  开头的字符'0'并不会被当作空白字符那样被过滤. 可以想像到, 读到任意数字(如这里的'0')之后的        非数字(如这里的'+'), 都将停止。

3  自己编写atoi需要注意的问题:

  (1) 字符串前的空白

  (2) 字符串所表示数值的正负号

  (3) 结束条件,遇到非数字或者字符'\0'结束

  (4) 考虑溢出,分别与int值所能表示的最大(0x7fffffff)和最小值(0x8000000)进行比较。而且最好考虑       32位机与64位机的区别。

  (5) 考虑异常输入情况下,用全局变量valid来标识,对于"+/-" "0" "+abc"需要进行区分。

4   自己实现atoi函数

//Nov.9,2014 Solomon
int myatoi(const char* str) {
    int n = 0;
    char sign;
    int c;

    while (isspace(*str))
        ++str;

    sign = *str;
    if (sign == '+' || sign == '-')
        ++str;
    while (isdigit(*str))
    {
        c = *str - '0';
//先用n与MAX/10进行比较: 若n>MAX/10(还要考虑n=MAX/10的情况), 说明将要溢出了
//提高溢出处理的健壮性,除法代替乘法
        if (sign != '-' && (n > INT_MAX/10 || (n == INT_MAX/10 && c >= INT_MAX%10)))
        {
            return INT_MAX;
        }
        else if (sign == '-' && (n > (unsigned)INT_MIN/10 
                              || (n == (unsigned)INT_MIN/10 && c >= (unsigned)INT_MIN%10)))
        {
            return INT_MIN;
        }
        n = n * 10 + c;
        ++str;
    }
    return sign == '-' ? -n : n;
}

5   测试函数

int main(){
	int N,i;
	char *str[STR_ELEM_NUM];
	memset(str,0,sizeof(str));

	printf("测试数据个数N:\n");
	scanf("%d",&N);
	for(i=0;i<N;i++){
		str[i] = (char*) malloc(STR_ELEM_NUM);
		// 如果不清缓冲区,scanf会把"\n"吃进,导致str[0] = "",少输入一个数据.
		fflush(stdin);	
		// str[i]是一个字符型指针,定义时指向不可用的地址,需要字符指针配内存空间
		scanf("%[^\n]",str[i]);
		fflush(stdin);	
	}
	printf("\n***************Result**************************\n");
	for(i =0;i<N;i++){
		printf("%d\n",myatoi(str[i]));
		free(str[i]);
	}
	return 0;
}

测试结果如下:

一个健壮性良好的atoi函数的实现_第3张图片

结论:

(1)   该atoi函数符合C11规定的所有内容。

(2)   程序采用除法代替加法的方式提高处理溢出的健壮性。

(3)   该算法逻辑清晰,鲁棒性强,是一个较优的atoi实现。



你可能感兴趣的:(C语言,字符串转数字,atoi,溢出处理)