前言
只有注重代码质量的程序员,才能写出鲁棒、稳定的大型软件。往往我们容易忽略一些边界条件、特殊输入等看似细枝末节但实则至关重要的地方。 我们在写代码时,应当不断反思程序在思路或者代码中存在那些漏洞。
一:模拟实现 atoi 函数
atoi 函数的主要功能就是将一个字符串转为整数,例如:将 “12345” –> 12345。
1.1 错误解法
这个题目很简单,很多人都会在三分钟之内写下如下不到10行的代码:
#include<iostream>
using namespace std;
int My_atoi(char* str){
int num = 0;
while (*str != 0){
num = num * 10 + *str - '0';
++str;
}
return num;
}
这个代码是有问题的,只要输入一个空指针,程序就会立即崩溃。其实看起来越是简单的问题,其中有可能就暗藏玄机。除了完成基本功能外,还需要考虑到特殊输入、边界控制、错误处理、是否溢出等问题。
这样一来,我们就不再认为这个题是一个简单题了。
1.2 正确解法
我们写出的代码不能只是完成最基本的功能,就本题来讲不能仅仅满足把字符串转换为整型这个最基本的要求,我们还需要考虑到以下问题:
- 特殊输入: 输入的字符串中有可能出现非数字字符或正负号,以及空指针。
- 考虑溢出: 最大的正整数以及最小的负整数溢出问题。
- 错误处理: 当输入的字符串不能转换为整数时,应当如何进行错误处理。
我们经过思考写出如下代码:
#include<iostream>
#include<string>
#include<assert.h>
using namespace std;
enum STATE{ // 定义两个枚举常量来表示状态
VALID, //合法
INVALID,//非法
};
enum STATE state = INVALID;
int My_atoi(const char* str){
assert(str); // 判空指针
long long ret = 0; // 定义比int存储范围还要大的类型,防止判断溢出时出错。
int flag = 1; // 正负号标记
if (*str == '\0'){ // 空字符串
state = INVALID;
return 0;
}
while (isspace(*str)){ // 空白字符
str++;
}
if (*str == '+'){ // 正负号
str++;
}
if (*str == '-'){
flag = -1;
str++;
}
while (*str){
if (isdigit(*str)){ // 判断是否为数字字符
ret = ret * 10 + flag*(*str - '0');
if (ret > INT_MAX || ret < INT_MIN){ // 判断溢出
state = INVALID;
return 0;
}
}
else{ // 异常字符
state = INVALID;
return 0;
}
str++;
}
state = VALID;
return ret;
}