<leetcode系列> String to Integer (atoi) 以及atoi源码实现
来源:互联网 发布:零基础学c语言视频 编辑:程序博客网 时间:2024/09/21 09:29
String to Integer (atoi)
Implement atoi to convert a string to an integer.
Hint: Carefully consider all possible input cases. If you want a challenge, please do not see below and ask yourself what are the possible input cases.
Notes: It is intended for this problem to be specified vaguely (ie, no given input specs). You are responsible to gather all the input requirements up front.
原题链接: https://leetcode.com/problems/string-to-integer-atoi/
题目大意: 类似于实现一个自己的atoi函数.
编译调试了很久, 遇到了不少感觉怪异的测试用例.列举如下:
还有一些没有列举出来. 大部分都是对数据溢出的处理问题.当数据溢出时, 正数的期望值是INT_MAX
, 负数的期望值是INT_MIN
.以及字符串开头的空格,符号位等.
其中数据溢出有两种情况.
1. 在已解析出的数值为214748364时, 而下一位的数值是8. 而int
的最大值是2147483647.则数据溢出
2. 在已解析出的数值为314748364时, 下一位无论是任何数, 均会数据溢出.
最终提交代码如下:
int myAtoi(char* str) { if (NULL == str) { return 0; } const int MAX_SIZE = 10; char* pStr = str; char* pSta = str;// 用于前置空格的排除 bool sig = false; // false -- +; true -- - int num = 0; int tmp = 0; int count = 0; // 记录当前数值长度 while ('\0' != *pStr) { if ((*pStr >= '0') && (*pStr <= '9')) { if (MAX_SIZE == count) { // 数据溢出 return sig ? INT_MIN : INT_MAX; } int tmp = *pStr - '0'; // 正负数分别计算 num = sig ? (10 * num - tmp) : (10 * num + tmp); ++count; } else { if (pStr == pSta) { switch (*pStr) { case '-': sig = true; break; case '+': sig = false; break; case ' ': ++pSta; break; default: return 0; } } else { break; } } ++pStr; } // 数据溢出 if (sig && (num > 0)) { return INT_MIN; } else if (!sig && (num < 0)) { return INT_MAX; } return num;}
显然, 在上述代码中, 肯定存在不少缺陷并且不够精炼.整个函数看起来繁琐, 各种标志位.效率当然也会大打折扣.
相信atoi函数对于大部分C/C++程序员都是一个比较熟悉的函数.在网站上查询了一下, atoi源代码确实写得很漂亮, 和我的代码比较起来, 简直一个天上一个地下啊.
可以看到atoi库函数的源码实现如下,供大家参阅:
int atoi(const char *nptr){ return (int) strtol(nptr, (char **) NULL, 10);}long __XL(strtol)(const char * __restrict str, char ** __restrict endptr, int base __LOCALE_PARAM ){ return __XL_NPP(_stdlib_strto_l)(str, endptr, base, 1 __LOCALE_ARG );}// 下述函数才是真正完成任务的函数// 实际调用时, str 是输入的nptr, endptr 是 NULL, base 是 10, sflag 是 1// 即 unsigned long _XL_NPP(_stdlib_strto_l)(nptr, NULL, 10, 1)unsigned long __XL_NPP(_stdlib_strto_l)(register const Wchar * __restrict str,Wchar ** __restrict endptr, int base,int sflag __LOCALE_PARAM ){ unsigned long number, cutoff;#if _STRTO_ENDPTR const Wchar *fail_char;#define SET_FAIL(X) fail_char = (X)#else#define SET_FAIL(X) ((void)(X)) /* Keep side effects. */#endif unsigned char negative, digit, cutoff_digit; assert(((unsigned int)sflag) <= 1); SET_FAIL(str); while (ISSPACE(*str)) { /* 忽略str中开头的空格 */ ++str; } /* 0 代表 正数; 1 代表 负数 */ negative = 0; switch(*str) { /* 注意到没有break, 无论*str是'+'或是'-',str均会自加 */ case '-': negative = 1; case '+': ++str; } /* 上述操作结束后, 将str前面的空格或是符号位均已跳过. 只跳过一个符号位,若出现"+-2"的情况, 那么当前*str是'-' */ if (!(base & ~0x10)) { /* 0x10的十进制是16, 当base等于16时, 该条件为真;否则为假; */ // 当然,还有可能有其他情况下会进入.比如base=0x******10(*代表任意数); base += 10; /* default is 10(26). */ if (*str == '0') { SET_FAIL(++str); base -= 2; /* Now base is 8 or 16 (24). */ if ((0x20|(*str)) == 'x') { /* WARNING: assumes ascii. */ ++str; base += base; /* Base is 16 (16 or 48). */ } } if (base > 16) { /* Adjust in case base wasn't dynamic. */ base = 16; } } number = 0; if (((unsigned)(base - 2)) < 35) { /* 最大能计算的进制是36进制. */ cutoff_digit = ULONG_MAX % base; // 计算当数值等于临界值时最大还能加上多大的数 cutoff = ULONG_MAX / base; // 计算判断数据溢出的临界值 do { // 判断每一位的数值; 代码执行类似如下 /* if (((Wuchar)(*str - '0')) <= 9) { digit = *str - '0'; } else { if (*str >= 'A') { // (0x20|(*str)) 将*str的第6位置1. // 即将所有大写字母的ascii码变为小写字母的ascii码, 而小写字母则不变 // 不清楚的同学可以百度ascii码表, 字母的大小写ascii码只是在二进制的第六位不同. // 大写字母的二进制第六位是0, 而小写的二进制第六位是1 digit = (((0x20|(*str)) - 'a' + 10)); } else { digit = 40; // 该位是非法字符. } } */ digit = (((Wuchar)(*str - '0')) <= 9) ? (*str - '0') : ((*str >= 'A') ? (((0x20|(*str)) - 'a' + 10)) /* WARNING: assumes ascii. */ : 40); // 遇到非法字符, 如16进制, 遇到了'?', 10进制,遇到了'A' if (digit >= base) { break; } SET_FAIL(++str); // 判断加上该位的数值后数据溢出 if ((number > cutoff) || ((number == cutoff) && (digit > cutoff_digit))) { number = ULONG_MAX; negative &= sflag; SET_ERRNO(ERANGE); } else { // 未溢出 number = number * base + digit; } } while (1); }#if _STRTO_ENDPTR if (endptr) { *endptr = (Wchar *) fail_char; }#endif { // ((unsigned long)(-(1+LONG_MIN))) == LONG_MAX, 但不知道为什么要这样获取long的最大值. // 当欲计算的数为负数时, tmp = LONG_MAX + 1;为正数时, tmp = LONG_MAX unsigned long tmp = ((negative) ? ((unsigned long)(-(1+LONG_MIN)))+1 : LONG_MAX); if (sflag && (number > tmp)) { number = tmp; SET_ERRNO(ERANGE); } } return negative ? (unsigned long)(-((long)number)) : number;}
- <leetcode系列> String to Integer (atoi) 以及atoi源码实现
- 【leetcode系列】String to Integer (atoi)
- LeetCode:String to Integer (atoi)
- LeetCode: String to Integer (atoi)
- LeetCode String to Integer(atoi)
- LeetCode :String to Integer (atoi)
- Leetcode: String to Integer (atoi)
- Leetcode : String to Integer (atoi)
- 【leetcode】String to Integer (atoi)
- [LeetCode]String to Integer (atoi)
- LeetCode-String to Integer (atoi)
- [leetcode] String to Integer (atoi)
- LeetCode - String to Integer (atoi)
- 【leetcode】String to Integer (atoi)
- LeetCode - String to Integer (atoi)
- LeetCode: String to Integer (atoi)
- Leetcode: String to Integer (atoi)
- [LeetCode] String to Integer (atoi)
- p=p->next
- 【黑马程序员】String.concat(),StringBuilder和“+”的区别
- 自定义view
- BST二叉查找树
- 【黑马程序员】集合框架(下)——Java复习笔记
- <leetcode系列> String to Integer (atoi) 以及atoi源码实现
- 数据挖掘中的离群点检测
- Laravel学习笔记一
- json解析几种格式
- laravel安装
- hibernate4配置
- Objective-C中将枚举转换成NSString的一种思路
- 分布式应用中服务监控
- Presistence