题目:实现atof/atoi,考虑正负号

一、Data Conversion

函数作用
atof把字符串转换为float型数字
atoi把字符串转换为int型数字
atol把字符串转换为long型数字
__toascii把字符转换为ascii码
tolower把字符转换为小写字符
toupper把字符转换为大写字符
abs取绝对值
strtod 
strtol 

 

二.atof

其实,这种字符串转换的函数,都无非做的同一件事情--解析字符串,根据不同的解析规则,执行不同的转换方式。

atof是借助strtod来实现的,主要步骤为:

  1. 1).解析空格  isspace
  2. 2).解析正负号  ‘+’or ‘-’
  3. 3).解析整数部分数字  isdigit
  4. 4).解析小数点及其后小数部分
    1. 5).解析科学计数部分
    2. 6).解析科学计数的正负号
    3. 7).还原组合数字

2.实现

   1: inline double tAtof(const tChar *pStr)
   2: {
   3:     return tStrtod(pStr, NULL);
   4: }
   5:  
   6: inline double tStrtod(const tChar *pStr, tChar **pEndStr)
   7: {
   8:     // advance beyond any leading whitespace
   9:     while( ::isspace(*pStr) )
  10:         ++pStr;
  11:  
  12:     // check for optional '+' or '-'
  13:     unsigned short uNegative = 0;
  14:     if( *pStr == _T('-') )
  15:     {
  16:         uNegative = 1;
  17:         ++pStr;
  18:     }
  19:     else if( *pStr == _T('+') )
  20:         ++pStr;
  21:  
  22:  
  23:     double dRet = 0.0;
  24:     int e = 0;
  25:     int c = 0;
  26:  
  27:     // 解析整数部分
  28:     while((c = *pStr) != _T('/0') && isdigit(c) )
  29:     {
  30:         dRet = dRet * 10.0 + (c - _T('0')); 
  31:         ++pStr;
  32:     }
  33:  
  34:     // 解析小数部分
  35:     if( c == _T('.') )
  36:     {
  37:         ++pStr;
  38:         while((c = *pStr) != _T('/0') && isdigit(c) )
  39:         {
  40:             dRet = dRet * 10.0 + (c - _T('0'));
  41:             e -= 1;
  42:  
  43:             ++pStr;
  44:         }
  45:     }
  46:  
  47:     // 解析科学计数
  48:     if( c == 'e' || c == 'E' )
  49:     {
  50:         int nSign = 1;
  51:         int nExponet = 0;
  52:  
  53:         c = *++pStr;
  54:  
  55:         // 解析正负号
  56:         if( c == _T('+') )
  57:             c = *++pStr;
  58:         else if( c == _T('-') )
  59:         {
  60:             nSign = -1;
  61:             c = *++pStr;
  62:         }
  63:  
  64:         while( isdigit(c) )
  65:         {
  66:             nExponet = nExponet * 10 + (c - _T('0'));
  67:             c = *pStr++;
  68:         }
  69:  
  70:         e += nExponet * nSign;
  71:     }
  72:  
  73:     // 还原组合数字
  74:     while(e > 0)
  75:     {
  76:         dRet *= 10.0;
  77:         --e;
  78:     }
  79:     while(e < 0)
  80:     {
  81:         dRet *= 0.1;
  82:         ++e;
  83:     }
  84:  
  85:     return uNegative ? -dRet : dRet;
  86: }

其实,思想挺简单的,只是有点长~。具体多琢磨琢磨就更清楚了。

3.测试

   1: tChar    *str = NULL;
   2: double  value = 0;
   3:  
   4: // An example of the atof function
   5: // using leading and training spaces.
   6: str = _T("  3336402735171707160320 ");
   7: value = CY_CRT::tAtof( str );
   8: cout << value << endl;
   9:  
  10: // Another example of the atof function
  11: // using the 'd' exponential formatting keyword.
  12: str = _T("3.1412764583d210");
  13: value = CY_CRT::tAtof( str );
  14: cout << value << endl;
  15:  
  16: // An example of the atof function
  17: // using the 'e' exponential formatting keyword.
  18: str = _T("-2309.12E-15");
  19: value = CY_CRT::tAtof( str );
  20: cout << value << endl;
  21:  
  22:  
  23: str = _T("-0.123e-10");
  24: value = CY_CRT::tAtof( str );
  25: cout << value << endl;

三、atoi

原理如下:

  1. 1)解析空格  tIsspace
  2. 2)判断正负号  ‘-’or  ’+’
  3. 3)strtol判断转换进制  16进制、8进制、10进制
  4. 4)解析数字字符
  5. 5)对每个字符转换为相应数字  tIsdigit  tIsalpha
  6. 6) 判断转换后的数字是否超过最大值
  7. 7)累加,基于转换进制
  8. 8)如果超过最大值则出错处理,负数就返回相反数
  9. 9)返回转换后的数字

1.实现

   1: inline int tAtoi(const tChar *pStr)
   2: {
   3:     return tStrtol(pStr, NULL, 10);
   4: }
   5:  
   6: inline long tStrtol(const tChar *pStr, tChar **pEndPtr, int nBase)
   7: {
   8:     /*
   9:         Skip white space and pick up leading +/- sign if any.
  10:         If nBase is 0, allow 0x for hex and 0 for octal, else assume decimal
  11:         If nBase if already 16, allow 0x
  12:     */
  13:  
  14:     const tChar *pStrTmp = pStr;
  15:     int c = 0;
  16:  
  17:     
  18:     do 
  19:     {
  20:         c = *pStrTmp++;            /* skip whitespace */
  21:     } while (tIsspace(c));
  22:  
  23:     int nNegative = 0;            /* remember minus sign */
  24:     if( c == _T('-') )
  25:     {
  26:         nNegative = 1;
  27:         c = *pStrTmp++;
  28:     }
  29:     else if( c == _T('+') )
  30:     {
  31:         c = *pStrTmp++;            /* skip sign */
  32:     }
  33:  
  34:     if( nBase < 0 || nBase == 1 || nBase > 36) 
  35:     {
  36:         /* bad base! */
  37:         if( pEndPtr )
  38:             /* store beginning of string in endptr */
  39:             *pEndPtr = const_cast(reinterpret_cast<const tChar *>(pStr));
  40:         return 0L;              /* return 0 */
  41:     }
  42:  
  43:     // 判断当前是否转换为16进制
  44:     if( (nBase == 0 || nBase == 16) &&
  45:         (c == _T('0')) &&
  46:         (*pStrTmp == _T('x') || *pStrTmp == _T('X')) )
  47:     {
  48:         c = pStrTmp[1];
  49:         pStrTmp += 2;
  50:         nBase = 16;
  51:     }
  52:     // 是否转换为8进制
  53:     if( nBase == 0 )
  54:         nBase = (c == _T('0') ? 8 : 10);
  55:  
  56:  
  57:     /* if our number exceeds this, we will overflow on multiply */
  58:     unsigned long ulCutOff = 0;
  59:     int nCutLim = 0;
  60:  
  61:     ulCutOff    = nNegative ? -(unsigned long)(LONG_MIN) : LONG_MAX;
  62:     nCutLim        = ulCutOff % static_cast<unsigned long>(nBase);
  63:     ulCutOff    /= static_cast<unsigned long>(nBase);
  64:  
  65:  
  66:     unsigned long acc =0;
  67:     int any = 0;
  68:     for(acc = 0, any = 0; ; c = *pStrTmp++)
  69:     {
  70:         /* convert c to value */
  71:         if( tIsdigit(c) )
  72:             c -= _T('0');
  73:         else if( tIsalpha(c) )
  74:             c -= tIsupper(c) ? _T('A') - 10 : _T('a') - 10;
  75:         else
  76:             break;         /* exit loop if bad digit found */
  77:  
  78:         if( c >= nBase )
  79:             break;
  80:  
  81:         /*    we now need to compute number = number * base + digval,
  82:             but we need to know if overflow occured.  This requires
  83:             a tricky pre-check. 
  84:         */
  85:         if( any < 0 || acc > ulCutOff || acc == ulCutOff && c > nCutLim )
  86:             any = -1;
  87:         else    
  88:         {
  89:             any = 1;
  90:             acc *= nBase;
  91:             acc += c;
  92:         }
  93:     }
  94:  
  95:     if( any < 0 )
  96:     {
  97:         /* we would have overflowed */
  98:         acc = nNegative ? LONG_MIN : LONG_MAX;
  99:         //throw std::overflow_error("LONG_MIN or LONG MAX");
 100:     }
 101:     /* negate result if there was a neg sign */
 102:     else if( nNegative )
 103:         acc = -acc;
 104:  
 105:     if( pEndPtr != 0 )
 106:         *pEndPtr = const_cast(reinterpret_cast<const tChar *>(any ? pStrTmp - 1: pStr));
 107:  
 108:     return acc;
 109: }

测试代码为

   1: tChar    *str = NULL;
   2: int     value = 0;
   3:  
   4: // An example of the atoi function.
   5: str = _T("  -2309 ");
   6: value = CY_CRT::tAtoi( str );
   7: wcout << value << endl;
   8:  
   9: // Another example of the atoi function.
  10: str = _T("31412764");
  11: value = CY_CRT::tAtoi( str );
  12: wcout << value << endl;


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值