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);
}
}