atoi和itoa函數實現

atoi函數是C語言庫提供的,是把字符串轉換成整型數和把字符串轉換成整型數。而itoa函數是廣泛應用的非標準C語言擴展函數,由於它不是標準C語言函數,所以不能在所有的編譯器中使用,它的功能是把一整數轉換爲字符串。
兩個函數功能很好理解,但是它們的實現需要考慮到很多問題,在面試中,很多面試官都會問atoi和itoa的實現,這可以很好的瞭解程序員編程的功底。
那麼在實現atoi一般需要考慮到那些情況呢?

  1. 首先是整數,很多人很自然的會忽略負整數。
  2. 其次是考慮到上溢和下溢
  3. 字符串以空格開始怎麼去處理
  4. 字符串中包含了除0-9之間的字符該怎麼去處理
#include <stdio.h>
 
#define MAX_INT ((1 << 31) - 1)
#define MIN_INT (-(1 << 31))
 
int atoi(const char *str){
    char *temp = str;
    int i = 0;
    int flags = 0;
    unsigned int sum = 0;
    while(*temp == ' ') ++temp ;
    if(*temp != '-' && *temp != '+' && (*temp < '0' || *temp > '9')){//第一個字符不是數字
        return 0;
    }
 
    if(*temp == '-'){ //第一個是負號
        flags = 1;
        ++temp;
    }else if(*temp == '+'){
        ++temp;
    }
 
    while(*temp >= '0' && *temp <= '9'){
        if(!flags){//上溢
            if(sum > MAX_INT / 10 || (sum == MAX_INT / 10 && (*temp > '7'))){
                return MAX_INT;
            }
 
        }else{//下溢
            if(sum > MAX_INT / 10 || (sum == MAX_INT / 10 && (*temp > '8'))){
                return MIN_INT;
            }
        }
 
        sum = sum * 10 + (*temp - '0');
        ++temp;
    }
 
    //if(flags){
        //sum *= -1;
    //}
    return flags ? (-1 * sum) : sum;
}
 
int main(){
    printf("%d\n", atoi("    0125464 c 646"));
    return 0;
}

ansi庫中的實現:

#include    <ctype.h>
#include    <stdlib.h>
 
int
atoi(register const char *nptr)
{
    return strtol(nptr, (char **) NULL, 10);
}
 
/*
 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
 * See the copyright notice in the ACK home directory, in the file "Copyright".
 */
/* $Header: strtol.c,v 1.4 90/05/11 15:22:19 eck Exp $ */
 
#include    <ctype.h>
#include    <errno.h>
#include    <limits.h>
#include    <stdlib.h>
 
static unsigned long
string2long(register const char *nptr, char **endptr,
            int base, int is_signed);
 
long int
strtol(register const char *nptr, char **endptr, int base)
{
    return (signed long)string2long(nptr, endptr, base, 1);
}
 
#define between(a, c, z)  ((unsigned) ((c) - (a)) <= (unsigned) ((z) - (a)))
 
static unsigned long
string2long(register const char *nptr, char ** const endptr,
            int base, int is_signed)
{
    register unsigned int v;
    register unsigned long val = 0;
    register int c;
    int ovfl = 0, sign = 1;
    const char *startnptr = nptr, *nrstart;
 
    if (endptr) *endptr = (char *)nptr;
    while (isspace(*nptr)) nptr++;
    c = *nptr;
 
    if (c == '-' || c == '+') {
        if (c == '-') sign = -1;
        nptr++;
    }
    nrstart = nptr;         /* start of the number */
 
    /* When base is 0, the syntax determines the actual base */
    if (base == 0)
        if (*nptr == '0')
            if (*++nptr == 'x' || *nptr == 'X') {
                base = 16;
                nptr++;
            }
            else    base = 8;
        else    base = 10;
    else if (base==16 && *nptr=='0' && (*++nptr =='x' || *nptr =='X'))
        nptr++;
 
    for (;;) {
        c = *nptr;
        if (between('0', c, '9')) {
            v = c - '0';
        } else
        if (between('a', c, 'z')) {
            v = c - 'a' + 0xa;
        } else
        if (between('A', c, 'Z')) {
            v = c - 'A' + 0xA;
        } else {
            break;
        }
        if (v >= base) break;
        if (val > (ULONG_MAX - v) / base) ovfl++;
        val = (val * base) + v;
        nptr++;
    }
    if (endptr) {
        if (nrstart == nptr) *endptr = (char *)startnptr;
        else *endptr = (char *)nptr;
    }
 
    if (!ovfl) {
        /* Overflow is only possible when converting a signed long. */
        if (is_signed
            && (   (sign < 0 && val > -(unsigned long)LONG_MIN)
            || (sign > 0 && val > LONG_MAX)))
            ovfl++;
    }
 
    if (ovfl) {
        errno = ERANGE;
        if (is_signed)
            if (sign < 0) return LONG_MIN;
            else return LONG_MAX;
        else return ULONG_MAX;
    }
    return (long) sign * val;
}

itoa實現注意事項:

  1. 忘記考慮負數;
  2. 忘記在末尾加上’\0′。

實現:

#include <stdlib.h>  
#include <stdio.h> 
 
char *itoa(int num,char *str,int radix){//num:int型原數,str:需轉換成的string,radix,原進制, 
     
    /* 索引表 */
    char index[]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    unsigned unum;/* 中間變量 */
    int i=0,j,k;
     
    /* 確定unum的值 */
    if(radix==10&&num<0){/* 十進制負數 */
        unum=(unsigned)-num;
        str[i++]='-';
    }else
        unum=(unsigned)num;/* 其他情況 */
    /* 逆序 */
    do{
        str[i++]=index[unum%(unsigned)radix];
        unum/=radix;
    }while(unum);
 
    str[i]='\0';
    /* 轉換 */
    if(str[0]=='-')
        k=1;/* 十進制負數 */
    else
        k=0;
    /* 將原來的“/2”改爲“/2.0”,保證當num在16~255之間,radix等於16時,也能得到正確結果 */
    for(j=k;j<(i-1)/2.0+k;j++){
        num=str[j];
        str[j]=str[i-j-1+k];
        str[i-j-1+k]=num;
    }
    return str;
}
 
int main(){
 
    int number = 01777777777777777777774; 
    char string[25]; 
 
    itoa(number, string, 10); 
 
    printf("integer = %d string = %s\n", number, string); 
    return 0; 
}

ansi庫實現

#define NUMBER_OF_DIGITS 16
 
void _uitoa(unsigned int value, char* string, unsigned char radix)
{
unsigned char index, i;
/* char buffer[NUMBER_OF_DIGITS]; */ /* space for NUMBER_OF_DIGITS + '\0' */
 
  index = NUMBER_OF_DIGITS;
  i = 0;
 
  do {
    string[--index] = '0' + (value % radix);
    if ( string[index] > '9') string[index] += 'A' - '9' - 1;
    value /= radix;
  } while (value != 0);
 
  do {
    string[i++] = string[index++];
  } while ( index < NUMBER_OF_DIGITS );
 
  string[i] = 0; /* string terminator */
}
 
void _itoa(int value, char* string, unsigned char radix)
{
  if (value < 0 && radix == 10) {
    *string++ = '-';
    _uitoa(-value, string, radix);
  }
  else {
    _uitoa(value, string, radix);
  }
}



發佈了22 篇原創文章 · 獲贊 5 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章