欢迎关注大数据技术架构与案例微信公众号:过往记忆大数据
过往记忆博客公众号iteblog_hadoop
欢迎关注微信公众号:
过往记忆大数据

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);
  }
}
本博客文章除特别声明,全部都是原创!
原创文章版权归过往记忆大数据(过往记忆)所有,未经许可不得转载。
本文链接: 【atoi和itoa函数实现】(https://www.iteblog.com/archives/224.html)
喜欢 (1)
分享 (0)
发表我的评论
取消评论

表情
本博客评论系统带有自动识别垃圾评论功能,请写一些有意义的评论,谢谢!
(3)个小伙伴在吐槽
  1. 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;

    jian2015-03-17 08:54 回复
  2. 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有什么区别?
    谢谢!

    lgjllgb2014-10-06 14:13 回复
  3. IMHO you've got the right ansewr!

    Allison2013-08-02 17:15 回复