题目一——给定一个字符串,如果该字符串符合人们日常书写一个整数的形式,返回int类
型的这个数;如果不符合或者越界返回-1或者报错。
思路:
首先要判断字符串能不能转成数字,之后要判断会不会在转成数字的时候发生溢出。
记录这个题主要不是为了记录怎么转换的,而是要记录一些防溢出的技巧
技巧一:用负数来接每一步的转换结果
cur='0'-input[i];
因为负数的最小值的绝对值的比正数的最大绝对值多一位,因此用负数更安全
#define MAX_val 2147483647
#define MIN_val -2147483648
技巧二:计算之前先判断一下是否会溢出,如果会,则不进行转换
int minq=MIN_val/10;
int minr=MIN_val%10;
//防溢出 前半部分代表乘10会溢出 后半部分代表乘10不会溢出,但是加上cur会溢出
if((res<minq)||(res==minq&&cur<minr)){
cerr<<"会发生溢出,转换失败"<<endl;
return 0;
}
res=res*10+cur;
技巧三:如果传入的是正数,而解析的过程我们是用负数来接的每一个结果,因此最后负数转正数之前,还要判断一下是否会发生溢出
//如果数字是正数,且res记录的结果值等于系统中负数的最小值
//此时将res转成正数会发生溢出
if(positive && res== MIN_val){
cerr<<"转为正数时会发生溢出"<<endl;
return 0;
}
return positive?-res:res;
上这道题的题解代码(很多的细节处理,都在代码的注释里):
#include<iostream>
#define MAX_val 2147483647
#define MIN_val -2147483648
using namespace std;
bool isValid(string input){
int i=0;
while(input[i]==' ')
i++;
//开头不是数字也不是负号
if((input[i]!='-')&&((input[i]<'0')||(input[i]>'9')))
return false;
//开头是负号,但是后面是0,或者只有一个负号
if((input[i]=='-')&&((input[i+1]=='0')||(input.length()==1)))
return false;
//以0开头且字符串长度大于1的
if((input[i]=='0')&&input.length()>1)
return false;
for(int i=1; i<input.length(); i++){
if((input[i]<'0')||(input[i]>'9'))
return false;
}
return true;
}
int calculate(string input){
if(input.length()==0) return 0;
if(!isValid(input)){
cerr<<"该数字不是正常书写的数字"<<endl;
return 0;
}
//判断是不是正数
bool positive=input[0]=='-'?false:true;
int minq=MIN_val/10;
int minr=MIN_val%10;
int res=0, cur=0;
for(int i=positive?0:1; i<input.length(); i++){
//获取负数(因为负数的最小值的绝对值的比正数的最大绝对值多一位,因此哟经负数存更安全)
//这是一个技巧
cur='0'-input[i];
//防溢出 前半部分代表乘10会溢出 后半部分代表乘10不会溢出,但是加上cur会溢出
if((res<minq)||(res==minq&&cur<minr)){
cerr<<"会发生溢出,转换失败"<<endl;
return 0;
}
res=res*10+cur;
}
//由于负数比正数的绝对值多一位,如果res的值刚刚好是负数的最大值
//也就是说转正数会发生溢出,因此此处抛出异常
if(positive && res== MIN_val){
cerr<<"转为正数时会发生溢出"<<endl;
return 0;
}
return positive?-res:res;
}
int main(){
string input;
while(getline(cin,input)){
cout<<calculate(input)<<endl;
}
return 0;
}
持续更新中————————————————————————————————————————————————