今天逛csdn的时候看到一篇讲atoi的博客,进去看了看,然后就想根据自己以前java中的转化仿造一把。
1. int 转 string
其实原理很简单(也是照搬JDK上的,稍微改了点). 加入有个整形 m,现需要转成字符串。可能你会想到每次除10取模然后再将余数变成字符。额,是的。但是这里并不想每次都除以10,而是100.这样每次就取出了两位,然后根据事先准备好的对应表直接将十位和个位取出来
2. string 转 int
其实atoi的内部实现就一句话 return (int)atol(...)。 就是先转成long然后再强转到int. 我想最主要的问题还是可能的溢出。假如一个很长的string转成int必然会溢出,如果转成long不溢出,再转成int必然会被截断,我现在想返回最大或最小的整形。
废话不说,直接上代码
#ifndef __STINRG_2_INT_H #define __STING_2_INT_H #include <string> using std::string; class StrIntConveter { public: static char DigitTens[]; static char DigitOnes[]; static int sizeTable[]; static int StringSize(int); static string ToString(int); //int 转string static void GetChars(int i,int index ,char buf[]); //内部实际使用 static bool ParseInt(const string&,int& ); //整形转string static bool ParseInt(const string& ,int&,int);//内部实际使用 protected: private: }; #endif #include "string2int.h" #include "character.h" char StrIntConveter::DigitTens[]={'0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '2', '2', '2', '2', '2', '2', '2', '2', '2', '2', '3', '3', '3', '3', '3', '3', '3', '3', '3', '3', '4', '4', '4', '4', '4', '4', '4', '4', '4', '4', '5', '5', '5', '5', '5', '5', '5', '5', '5', '5', '6', '6', '6', '6', '6', '6', '6', '6', '6', '6', '7', '7', '7', '7', '7', '7', '7', '7', '7', '7', '8', '8', '8', '8', '8', '8', '8', '8', '8', '8', '9', '9', '9', '9', '9', '9', '9', '9', '9', '9', }; char StrIntConveter::DigitOnes[]={'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', }; int StrIntConveter::sizeTable[]= { 9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999, INT_MAX }; int StrIntConveter::StringSize(int x) { for (int i=0;;i++) { if (x<=sizeTable[i]) return i+1; } } string StrIntConveter::ToString(int i) { if (i==INT_MIN) return "-2147483648"; //获得要转换的整数一共有多少位,包含符号位 int size=(i<0)?StringSize(-i)+1:StringSize(i); char* tmp=new char[size+1]; tmp[size]='\0'; //以为new char时会自动将数据清0.没想到啊。所以这里必须显示的设置一下 GetChars(i,size,tmp); string retValue= string(tmp); delete [] tmp; return retValue; } void StrIntConveter::GetChars(int i,int index ,char buf[]) { int q,r; int charPos=index; char sign=0; //符号位 if (i<0) { sign='-'; i=-i; } //为了提高效率,每次产生2位,然后尽量用位运算 while (i>100) { q=i/100; r=i-((q<<6)+(q<<5)+(q<<2));//取2位的余数 i=q; buf[--charPos]=DigitOnes[r]; buf[--charPos]=DigitTens[r]; } //JDK处理小于65535的情况不好用c++处理,所以用了自己的办法 if(q==100){ buf[--charPos] = '0'; buf[--charPos] = '0'; buf[--charPos] = '1'; }else if(q<10){ buf[--charPos]=DigitOnes[i]; }else{ buf[--charPos]=DigitOnes[q]; buf[--charPos]=DigitTens[i]; } if(sign!=0){ buf[--charPos]=sign; } } bool StrIntConveter::ParseInt(const string&s , int & retValue) { if (ParseInt(s,retValue,10)) return true; return false; } bool StrIntConveter::ParseInt(const string &s, int &retValue, int radix) { if (s.empty() || s=="") { retValue=0; return true; } if (radix<Character::MIN_RADIX || radix>Character::MAX_RADIX) return false; bool negative=false; //表示正负 int result=0; //转换结果 int limit; //极限范围 int multmin; //在 *radix之前的极限 int i=0,maxl=s.size(); int tmpDigit; //每次取出的字符 if (maxl>0) { if (s.at(0)=='-') { negative=true; limit=INT_MIN; i++; }else { limit=-INT_MAX; //在这里也将正数先表示为负数,返回结果的时候再判断(所有都为了统一后面的操作) } multmin=limit/radix; if (i<maxl) { tmpDigit=Character::Digit(s.at(i++),radix); if (tmpDigit<0) { return false; }else result=-tmpDigit; } while (i<maxl) { tmpDigit=Character::Digit(s.at(i++),radix); if (tmpDigit<0) { return false; } if (result<multmin) //已经到极限了 { //这里会出现溢出,但是为了程序健壮将直接返回最大值 result=limit; break; } result*=radix; if (result<limit+tmpDigit) { result=limit; break; } result-=tmpDigit; } } else { retValue=0; return true; } if (negative) { if (i>1) { retValue=result; return true; }else //仅仅只有一个 ‘-’ { return false; } }else { retValue=-result; return true; } }
#ifndef __CHARACTER_H #define __CHARACTER_H class Character { public: static int MIN_RADIX; //最小进制 static int MAX_RADIX; //最大进制 static char MIN_CHAR; static char MAX_CHAR; static int Digit(char ch,int radix); protected: private: }; #endif #include "character.h" #include <ctype.h> int Character::MIN_RADIX=2; int Character::MAX_RADIX=36; char Character::MIN_CHAR='\0'; char Character::MAX_CHAR=0xff; //将一个radix进制的数转换成对应的十进制 //其中负数表示失败 int Character::Digit(char ch, int radix) { if (radix<MIN_RADIX || radix>MAX_RADIX) { return -1; } if (radix<=10) { if (ch>='0' && ch<='9') { return ch-'0'; } return -1; } int upperChar=toupper(ch); int limit='A'+radix-11; if (upperChar>limit) return -1; return 10+upperChar-'A'; }
这是些测试用的
#include <iostream> #include <string> #include "string2int.h" using std::cout; using std::cin; using std::string; int main() { /*int i=0; cout<<"请输入要转成string的 整数\n"; cin>>i; while (i!=1) { cout<<StrIntConveter::ToString(i)<<"\n"; cin>>i; }*/ int result=0; string tmp; cout<<"请输入要转成int 的string\n"; cin>>tmp; while (tmp!="quit") { if (StrIntConveter::ParseInt(tmp,result)) { cout<<"转换的结果是"<<result<<"\n"; cin>>tmp; }else{ cout<<"转换失败\n"; break; } } system("pause"); return 0; }