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

来源:互联网 发布:示剑网络怎么样 编辑:程序博客网 时间:2024/06/06 19:05

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

1 函数说明

C89中的说明:

  头文件

  stdlib.h

  函数原型

  intatoi(const char *nptr);

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

  返回值

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

  说明

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

 

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

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

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

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 Solomonint 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;}

测试结果如下:


结论:

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

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

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



0 0
原创粉丝点击