面试题: 字符串转整型 终结者

前言

很久之前写过一篇奶头乐,关于简单面试题总结.  重新翻阅看到这个题目.

/*
 * 写一个函数 "将整数字符串转成整数"
 */

随着代码手感增强, 想为这个问题写个终结者系列.  缅怀下曾经的自己. 

🙏

奇奇怪怪编码 - 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 <stdio.h>
#include <limits.h>
#include <stddef.h>
#include <stdint.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

/* 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 来判断越界, 当然这种做法前头已经说了, 存在潜在问题, 不推荐.  

这类数据转换函数很多是跨学科, 对于普通工程师而言有点吃力, 感谢相关科学家或专业人士铸就了今天的基础. 

希望以上思路能终结这个面试题. 欢迎大家补充更优更完备

 

posted on 2022-03-08 19:09  喜欢兰花山丘  阅读(395)  评论(0编辑  收藏  举报