前言
很久之前写过一篇奶头乐,关于简单面试题总结. 重新翻阅看到这个题目.
/* * 写一个函数 "将整数字符串转成整数" */
随着代码手感增强, 想为这个问题写个终结者系列. 缅怀下曾经的自己.
奇奇怪怪编码 - https://www.emojiall.com/zh-hans/code/1F64F
正文
我们审视下这个问题, 整数字符串转成整数. 那么意味着有效字符仅有 "+-0123456789".
其中整数常见有 short, int , long, long long 等对吧. 大部分人会写成 string convert int.
这里存在一个潜在模糊知识是, C 标准规定 sizeof(long long) >= sizeof (long) >= sizeof(int) >= sizeof(short).
但没有明说具体多大, 这就意味着不同平台实现上可以自由发挥. 例如 sizeof (long) 多数 linux 平台是 8, window 是 4.
所以这里不写那么复杂. 简单点 string convet int32.
因此写题目开始可以和对方一块交流探讨下. 有了 string convert int32 经验加一些平台分支宏搞出 string convert int 也容易.
那我们开始吧.
相关素材 : https://github.com/wangzhione/temp/blob/master/code/offer1/67_string_int.c#L17-L75
#include#include #include #include #include #include #include <string.h> #include /* describe : 写一个完整 string to int32_t */ #define NUMBER_SUCCESS 0 // 转换成功 #define NUMBER_INVALID -2 // 非法字符 #define NUMBER_BORDER -3 // 数值越界 int str2int32(const char * str, int32_t * res) { if (str == NULL) { return NUMBER_INVALID; } if (*str == 0) { if (res) *res = 0; return NUMBER_SUCCESS; } // int32_t int Signed 32 4 -2,147,483,648 2,147,483,647 // + - 1 字节, 后面 max size = 10 // 如果 max size = 10, 那么 max size = 9 的时候最大值为 2,147,483,64 int32_t num = 0; bool minus = false; // 标识负数 if (*str == '+' || *str == '-') { minus = *str++ == '-'; } char c; int count = 0; while (++count < 10 && (c = *str++) != 0) { if (c >= '0' && c <= '9') { // 合理字符 num = 10 * num + c - '0'; } else { return NUMBER_INVALID; } } if (c != 0) { if (num > 214748364) { // size = 9 时候最大值 return NUMBER_BORDER; } c = *str++; if (*str != 0) { // size > 10 越界 return NUMBER_BORDER; } if ((c >= '0' && c <= '7') || (c == '8' && minus)) { if (c == '8') { if (res) *res = -2147483648; return NUMBER_SUCCESS; } num = 10 * num + c - '0'; } else { return NUMBER_BORDER; } } num = minus ? -num : num; if (res) *res = num; return NUMBER_SUCCESS; } // build: // gcc -g -O3 -Wall -Wextra -Werror -o 67_string_int 67_string_int.c // int main(void) { int code; int32_t num; const char * str; num = 0; str = NULL; code = str2int32(str, &num); printf("code = %d, str = %s, num = %d\n", code, str, num); assert(code == NUMBER_INVALID && num == 0); num = 0; str = "-1"; code = str2int32(str, &num); printf("code = %d, str = %s, num = %d\n", code, str, num); assert(code == NUMBER_SUCCESS && num == -1); num = 0; str = "1234A"; code = str2int32(str, &num); printf("code = %d, str = %s, num = %d\n", code, str, num); assert(code == NUMBER_INVALID); num = 0; str = "2147483647"; code = str2int32(str, &num); printf("code = %d, str = %s, num = %d\n", code, str, num); assert(code == NUMBER_SUCCESS && num == 2147483647); num = 0; str = "-2147483648"; code = str2int32(str, &num); printf("code = %d, str = %s, num = %d\n", code, str, num); assert(code == NUMBER_SUCCESS && num == -2147483648); num = 0; str = "-2147483649"; code = str2int32(str, &num); printf("code = %d, str = %s, num = %d\n", code, str, num); assert(code == NUMBER_BORDER); num = 0; str = "2147483648"; code = str2int32(str, &num); printf("code = %d, str = %s, num = %d\n", code, str, num); assert(code == NUMBER_BORDER); exit(EXIT_SUCCESS); }
整体代码分两部分实现 str2int32 和 assert 单元测试 . 单元测试怎么强调都不为过, 这是成为高手必经之路.
其中实现围绕核心思路是下面这些数学知识.
int32_t int Signed 32 4 -2,147,483,648 2,147,483,647
实现层面没有借助 long 来判断越界, 当然这种做法前头已经说了, 存在潜在问题, 不推荐.
这类数据转换函数很多是跨学科, 对于普通工程师而言有点吃力, 感谢相关科学家或专业人士铸就了今天的基础.
希望以上思路能终结这个面试题. 欢迎大家补充更优更完备解法.