> 文章列表 > 模拟实现atoi(详解)

模拟实现atoi(详解)

模拟实现atoi(详解)

前言:内容包括atoi函数的介绍使用及模拟实现,代码解读

atoi函数:将字符串转换成整数

构造:

int atoi (const char * str);

头文件:

#include <stdlib.h> 

使用:

#include<stdio.h>
#include<stdlib.h>
int main()
{int ret = atoi("1234");printf("%d", ret);return 0;
}

模拟实现:

 大致思路:

设计atoi函数考虑以下问题:

1 空指针NULL问题

2 空字符串问题

3 非数字字符问题

4 越界溢出问题

代码实现:atoi

#include<stdio.h>
#include<assert.h>
#include<ctype.h>
#include<limits.h>
enum State
{VALID,INVALID
};
enum State s = INVALID;//非法的状态int my_atoi(const char* str)
{//空指针assert(str);//空字符串if (*str == '\\0'){return 0;}//+ -int flag = 1;if (*str == '+'){str++;}else if (*str == '-'){flag = -1;str++;}long long ret = 0;while (*str){if (isdigit(*str)){ret = ret * 10 + flag*(*str - '0');if (ret > INT_MAX || ret < INT_MIN){return (int)ret;}}else{return (int)ret;}str++;}if (*str == '\\0'){s = VALID;}return(int)ret;}int main()
{int ret = my_atoi("1234a");if (s == INVALID){printf("非法转换:%d", ret);}else{printf("合法转换:%d", ret);}return 0;
}

代码解读:

 part 1

enum State
{VALID,INVALID
};
enum State s = INVALID;//非法的状态

设计枚举类型,列出转换的所有可能:合法转换,非法转换

当my_atoi函数实现了非法转换,则我们返回一个值的同时标志它是非法转换

故而我们定义了一个全局变量s,用于辨别返回的值是非法转换还是合法转换

s初始化为INVALID,是因为非法的情况有很多种,但是合法的情况仅有一种,所以当出现合法转换之后,我们只需要更改一次s的值为VALID,更为方便

part 2

    //空指针assert(str);//空字符串if (*str == '\\0'){return 0;}//+ -int flag = 1;if (*str == '+'){str++;}else if (*str == '-'){flag = -1;str++;}

空指针问题:

用assert函数来断言,判断str指针是否为空,若其为空,这处会报错

assert函数的头文件:

#include <assert.h> 

空字符串问题:

空字符串的第一个元素就是'\\0',则我们设定返回0,但是存在另一种情况:要被转换的字符串它的

内容就是一个数字字符0,则也需要返回0,但是这是合法转换

解决:定义一个枚举类型的全局变量,初始化为INVALID,这样当非法转换也返回0后,依据这个全局变量的值,就能被识别

+,-问题:

 flag来标记+,-

flag初始化为1,默认输入的字符串被转换后是正数

若是字符串的第一个元素是“-”,则让flag = -1,同时str++,指向有效的数字字符

part 3

    long long ret = 0;while (*str){if (isdigit(*str)){ret = ret * 10 + flag*(*str - '0');if (ret > INT_MAX || ret < INT_MIN)//溢出{return (int)ret;}}else{return (int)ret;}str++;}

非数字字符问题和越界溢出问题都需要我们在遍历字符串时才能被发现

遍历字符串:

若是当前遍历到的元素是数字字符:计算求和

"1234'' ---->1234

得到1:0*10+'1'-'0' = 1

变成12:1*10+'2'-'0' = 12

变成123:12*10+'3'-'0' = 123

变成1234:123*10+'4'-'0' = 1234

数字字符-'0' = 数字

求和之后判断是否溢出,所以我们需要将ret设置成long long 类型,因为my_atoi返回的是int类型,long long类型的ret能够存下超过int类型的值(溢出),这样就能判断溢出否了,但若ret为int类型,则永远不可能出现溢出问题,即使ret*10+(*str-'0')算出的一个数超过了int类型,但由于被存入int类型的ret中,发生截断,则一定不会超出int

ret是long long 类型,但返回类型是int,所以在返回ret时需要将ret强制转换为int类型

不是数字字符:非法转换,直接返回

part 4

    if (*str == '\\0'){s = VALID;}return(int)ret;

当遍历整个字符串结束后,仍没有提前return,则说明输入的字符串全部都是由数字字符组成的,则ret中是合法转换的结果,此时需将全局变量s的值置成VALID

part 5

int main()
{int ret = my_atoi("1234a");if (s == INVALID){printf("非法转换:%d", ret);}else{printf("合法转换:%d", ret);}return 0;
}

当my_atoi函数返回一个值后,根据全局变量s的值来判断此次转换是非法转换还是合法转换