atoi函数是C语言库提供的,是把字符串转换成整型数和把字符串转换成整型数。而itoa函数是广泛应用的非标准C语言扩展函数,由于它不是标准C语言函数,所以不能在所有的编译器中使用,它的功能是把一整数转换为字符串。
两个函数功能很好理解,但是它们的实现需要考虑到很多问题,在面试中,很多面试官都会问atoi和itoa的实现,这可以很好的了解程序员编程的功底。
那么在实现atoi一般需要考虑到那些情况呢?
- 首先是整数,很多人很自然的会忽略负整数。
- 其次是考虑到上溢和下溢
- 字符串以空格开始怎么去处理
- 字符串中包含了除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实现注意事项:
- 忘记考虑负数;
- 忘记在末尾加上'\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); } }本博客文章除特别声明,全部都是原创!
原创文章版权归过往记忆大数据(过往记忆)所有,未经许可不得转载。
本文链接: 【atoi和itoa函数实现】(https://www.iteblog.com/archives/224.html)
for function atoi:
char *temp = str;
错了。不能把const char * convert to char *.
you should do the followings:
char * temp = new char[strlen(str)+1];
strcpy(temp, str);
instead of char *temp = str;
ansi库中的实现:几行语句
066 c = *nptr;
067 if (between('0', c, '9')) {
068 v = c - '0';
069 } else
070 if (between('a', c, 'z')) {
071 v = c - 'a' + 0xa;
072 } else
073 if (between('A', c, 'Z')) {
074 v = c - 'A' + 0xA;
075 } else {
076 break;
077 }
该怎么理解?字母的情况,为什么加0xa或者0xA。另外,0xa与0xA有什么区别?
谢谢!
IMHO you've got the right ansewr!